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(const float *data, int size, float *position,
00310 int minPoints)
00311 {
00312 int i;
00313 int count = 0;
00314 float *copy;
00315 float max, median, level, pos, variance, uniformVariance;
00316 double sum, weights;
00317
00318
00319 if (data == NULL)
00320 return 1;
00321
00322 if (size < 5)
00323 return 1;
00324
00325
00326
00327
00328
00329
00330 copy = (float *) cpl_malloc(size*sizeof(float));
00331 for (i = 0; i < size; i++)
00332 copy[i] = data[i];
00333 median = cpl_tools_get_median_float(copy, size);
00334 cpl_free(copy);
00335
00336
00337
00338
00339
00340
00341 max = data[0];
00342 for (i = 1; i < size; i++)
00343 if (data[i] > max)
00344 max = data[i];
00345
00346
00347
00348
00349
00350
00351
00352 if (max-median < 0.00001)
00353 return 1;
00354
00355
00356
00357
00358
00359
00360
00361 level = (max + median) / 2;
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 count = 0;
00372 for (i = 0, sum = 0., weights = 0.; i < size; i++) {
00373 if (data[i] > level) {
00374 count++;
00375 weights += (data[i] - median);
00376 sum += i * (data[i] - median);
00377 }
00378 }
00379
00380
00381
00382
00383
00384
00385
00386 if (count < minPoints)
00387 return 1;
00388
00389 pos = sum / weights;
00390 for (i = 0, sum = 0., weights = 0.; i < size; i++) {
00391 if (data[i] > level) {
00392 weights++;
00393 sum += (i - pos) * (i - pos);
00394 }
00395 }
00396 variance = sqrt(sum / weights);
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406 uniformVariance = sqrt(size*size/3 - pos*size + pos*pos);
00407
00408 if (variance > 0.8 * uniformVariance)
00409 return 1;
00410
00411 *position = pos + 0.5;
00412
00413 return 0;
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
00463 static double values_to_dx(double v1, double v2, double v3)
00464 {
00465
00466 static double epsilon = 0.00000001;
00467 double r = 2.0;
00468
00469
00470 if (v1 > v2 || v3 > v2)
00471 return r;
00472
00473 if (2 * v2 - v1 - v3 < epsilon)
00474 return r;
00475
00476 r = 0.5 * (v3 - v1) / (2 * v2 - v3 - v1);
00477
00478 return r;
00479
00480 }
00481
00482
00483
00484
00485
00486
00487
00488 static float *min_filter(float *buffer, int length, int size)
00489 {
00490 float *minf = cpl_calloc(length, sizeof(float));
00491 float min;
00492 int start = size / 2;
00493 int end = length - size / 2;
00494 int i, j;
00495
00496
00497 for (i = start; i < end; i++) {
00498 min = buffer[i-start];
00499 for (j = i - start + 1; j <= i + start; j++)
00500 if (min > buffer[j])
00501 min = buffer[j];
00502 minf[i] = min;
00503 }
00504
00505 for (i = 0; i < start; i++)
00506 minf[i] = minf[start];
00507
00508 for (i = end; i < length; i++)
00509 minf[i] = minf[end-1];
00510
00511 return minf;
00512 }
00513
00514
00515
00516
00517
00518
00519
00520 static float *max_filter(float *buffer, int length, int size)
00521 {
00522 float *maxf = cpl_calloc(length, sizeof(float));
00523 float max;
00524 int start = size / 2;
00525 int end = length - size / 2;
00526 int i, j;
00527
00528
00529 for (i = start; i < end; i++) {
00530 max = buffer[i-start];
00531 for (j = i - start + 1; j <= i + start; j++)
00532 if (max < buffer[j])
00533 max = buffer[j];
00534 maxf[i] = max;
00535 }
00536
00537 for (i = 0; i < start; i++)
00538 maxf[i] = maxf[start];
00539
00540 for (i = end; i < length; i++)
00541 maxf[i] = maxf[end-1];
00542
00543 return maxf;
00544 }
00545
00546
00547
00548
00549
00550
00551
00552 static float *smo_filter(float *buffer, int length, int size)
00553 {
00554 float *smof = cpl_calloc(length, sizeof(float));
00555 double sum;
00556 int start = size / 2;
00557 int end = length - size / 2;
00558 int i, j;
00559
00560
00561 for (i = start; i < end; i++) {
00562 sum = 0.0;
00563 for (j = i - start; j <= i + start; j++)
00564 sum += buffer[j];
00565 smof[i] = sum / size;
00566 }
00567
00568 for (i = 0; i < start; i++)
00569 smof[i] = smof[start];
00570
00571 for (i = end; i < length; i++)
00572 smof[i] = smof[end-1];
00573
00574 return smof;
00575 }
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596 static cpl_polynomial *read_global_distortion(cpl_table *global, int row)
00597 {
00598 cpl_polynomial *poly = NULL;
00599 int p[2];
00600 int degree = 2;
00601 int null;
00602 double coeff;
00603
00604 char name[MAX_COLNAME];
00605
00606
00607 for (p[0] = 0; p[0] <= degree; p[0]++) {
00608 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
00609 snprintf(name, MAX_COLNAME, "a%d%d", p[0], p[1]);
00610 coeff = cpl_table_get_double(global, name, row, &null);
00611 if (null)
00612 continue;
00613 if (poly == NULL)
00614 poly = cpl_polynomial_new(2);
00615 cpl_polynomial_set_coeff(poly, p, coeff);
00616 }
00617 }
00618
00619 return poly;
00620 }
00621
00622 static cpl_table *write_global_distortion(cpl_table *global, int row,
00623 cpl_polynomial *poly)
00624 {
00625 cpl_table *table;
00626 int p[2];
00627 int degree = 2;
00628 int nrow = 10;
00629
00630 char name[MAX_COLNAME];
00631
00632
00633 if (global) {
00634 table = global;
00635 }
00636 else {
00637 table = cpl_table_new(nrow);
00638 for (p[0] = 0; p[0] <= degree; p[0]++) {
00639 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
00640 snprintf(name, MAX_COLNAME, "a%d%d", p[0], p[1]);
00641 cpl_table_new_column(table, name, CPL_TYPE_DOUBLE);
00642 }
00643 }
00644 }
00645
00646 if (poly) {
00647 for (p[0] = 0; p[0] <= degree; p[0]++) {
00648 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
00649 snprintf(name, MAX_COLNAME, "a%d%d", p[0], p[1]);
00650 cpl_table_set_double(table, name, row,
00651 cpl_polynomial_get_coeff(poly, p));
00652 }
00653 }
00654 }
00655
00656 return table;
00657 }
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669 #define SEGNO(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
00670 static int robustLinearFit(cpl_bivector *list, double *a, double *b,
00671 double *abdev)
00672 {
00673 cpl_vector *vx;
00674 cpl_vector *vy;
00675 cpl_vector *va;
00676
00677 double aa, bb, bcomp, b1, b2, del, abdevt, f, f1, f2, sigb, temp, d, sum;
00678 double sx, sy, sxy, sxx, chisq;
00679 double *arr;
00680 double aa_ls, bb_ls;
00681 double *x;
00682 double *y;
00683 int np;
00684 int iter;
00685 int max_iterate = 30;
00686 int i;
00687
00688
00689 np = cpl_bivector_get_size(list);
00690 vx = cpl_bivector_get_x(list);
00691 vy = cpl_bivector_get_y(list);
00692 x = cpl_vector_get_data(vx);
00693 y = cpl_vector_get_data(vy);
00694
00695 sx = sy = sxx = sxy = 0.00;
00696 for (i = 0; i < np; i++) {
00697 sx += x[i];
00698 sy += y[i];
00699 sxy += x[i] * y[i];
00700 sxx += x[i] * x[i];
00701 }
00702
00703 del = np * sxx - sx * sx;
00704 aa_ls = aa = (sxx * sy - sx * sxy) / del;
00705 bb_ls = bb = (np * sxy - sx * sy) / del;
00706
00707 chisq = 0.00;
00708 for (i = 0; i < np; i++) {
00709 temp = y[i] - (aa+bb*x[i]);
00710 temp *= temp;
00711 chisq += temp;
00712 }
00713
00714 va = cpl_vector_new(np);
00715 arr = cpl_vector_get_data(va);
00716 sigb = sqrt(chisq/del);
00717 b1 = bb;
00718
00719 bcomp = b1;
00720 sum = 0.00;
00721 for (i = 0; i < np; i++) {
00722 arr[i] = y[i] - bcomp * x[i];
00723 }
00724 aa = cpl_vector_get_median_const(va);
00725 abdevt = 0.0;
00726 for (i = 0; i < np; i++) {
00727 d = y[i] - (bcomp * x[i] + aa);
00728 abdevt += fabs(d);
00729 if (y[i] != 0.0)
00730 d /= fabs(y[i]);
00731 if (fabs(d) > 1e-7)
00732 sum += (d >= 0.0 ? x[i] : -x[i]);
00733 }
00734 f1 = sum;
00735
00736 b2 = bb + SEGNO(3.0 * sigb, f1);
00737
00738 bcomp = b2;
00739 sum = 0.00;
00740 for (i = 0; i < np; i++) {
00741 arr[i] = y[i] - bcomp * x[i];
00742 }
00743 aa = cpl_vector_get_median_const(va);
00744 abdevt = 0.0;
00745 for (i = 0; i < np; i++) {
00746 d = y[i] - (bcomp * x[i] + aa);
00747 abdevt += fabs(d);
00748 if (y[i] != 0.0)
00749 d /= fabs(y[i]);
00750 if (fabs(d) > 1e-7)
00751 sum += (d >= 0.0 ? x[i] : -x[i]);
00752 }
00753 f2 = sum;
00754
00755 if (fabs(b2-b1)<1e-7) {
00756 *a = aa;
00757 *b = bb;
00758 *abdev = abdevt / (double)np;
00759 cpl_vector_delete(va);
00760 return 0;
00761 }
00762
00763 iter = 0;
00764 while (f1*f2 > 0.0) {
00765 bb = 2.0*b2-b1;
00766 b1 = b2;
00767 f1 = f2;
00768 b2 = bb;
00769
00770 bcomp = b2;
00771 sum = 0.00;
00772 for (i = 0; i < np; i++) {
00773 arr[i] = y[i] - bcomp * x[i];
00774 }
00775 aa = cpl_vector_get_median_const(va);
00776 abdevt = 0.0;
00777 for (i = 0; i < np; i++) {
00778 d = y[i] - (bcomp * x[i] + aa);
00779 abdevt += fabs(d);
00780 if (y[i] != 0.0)
00781 d /= fabs(y[i]);
00782 if (fabs(d) > 1e-7)
00783 sum += (d >= 0.0 ? x[i] : -x[i]);
00784 }
00785 f2 = sum;
00786 iter++;
00787 if (iter >= max_iterate)
00788 break;
00789 }
00790 if (iter >= max_iterate) {
00791 *a = aa_ls;
00792 *b = bb_ls;
00793 *abdev = -1.0;
00794 cpl_vector_delete(va);
00795 return 1;
00796 }
00797
00798 sigb = 0.01 * sigb;
00799 while (fabs(b2-b1) > sigb) {
00800 bb = 0.5 * (b1 + b2);
00801 if ((fabs(bb-b1) < 1e-7) || (fabs(bb-b2) < 1e-7))
00802 break;
00803 bcomp = bb;
00804 sum = 0.0;
00805 for (i = 0; i < np; i++) {
00806 arr[i] = y[i] - bcomp * x[i];
00807 }
00808 aa = cpl_vector_get_median_const(va);
00809 abdevt = 0.0;
00810 for (i = 0; i < np; i++) {
00811 d = y[i] - (bcomp * x[i] + aa);
00812 abdevt += fabs(d);
00813 if (y[i] != 0.0)
00814 d /= fabs(y[i]);
00815 if (fabs(d) > 1e-7)
00816 sum += (d >= 0.0 ? x[i] : -x[i]);
00817 }
00818 f = sum;
00819
00820 if (f*f1 >= 0.0) {
00821 f1=f;
00822 b1=bb;
00823 }
00824 else {
00825 f2=f;
00826 b2=bb;
00827 }
00828 }
00829 cpl_vector_delete(va);
00830 *a = aa;
00831 *b = bb;
00832 *abdev = abdevt / np;
00833 return 0;
00834 }
00835 #undef SEGNO
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847 cpl_table *mos_hough_table(cpl_table *table, const char *x, const char *y)
00848 {
00849 cpl_table *output;
00850 double *xdata;
00851 double *ydata;
00852 double *xodata;
00853 double *yodata;
00854 int npoints;
00855 int opoints;
00856 int i, j, k;
00857
00858
00859 npoints = cpl_table_get_nrow(table);
00860 opoints = npoints*(npoints-1)/2;
00861
00862 output = cpl_table_new(opoints);
00863 cpl_table_new_column(output, "m", CPL_TYPE_DOUBLE);
00864 cpl_table_new_column(output, "q", CPL_TYPE_DOUBLE);
00865 cpl_table_fill_column_window_double(output, "m", 0, opoints, 0.0);
00866 cpl_table_fill_column_window_double(output, "q", 0, opoints, 0.0);
00867
00868 xodata = cpl_table_get_data_double(output, "m");
00869 yodata = cpl_table_get_data_double(output, "q");
00870
00871 cpl_table_cast_column(table, x, "x", CPL_TYPE_DOUBLE);
00872 cpl_table_cast_column(table, y, "y", CPL_TYPE_DOUBLE);
00873
00874 xdata = cpl_table_get_data_double(table, "x");
00875 ydata = cpl_table_get_data_double(table, "y");
00876
00877 k = 0;
00878 for (i = 0; i < npoints; i++) {
00879 for (j = i+1; j < npoints; j++) {
00880 xodata[k] = (ydata[i]-ydata[j])/(xdata[i]-xdata[j]);
00881 yodata[k] = ydata[i] - xodata[k] * xdata[i];
00882 k++;
00883 }
00884 }
00885
00886 if (k != opoints)
00887 printf("Assert k = %d, expected %d\n", k, opoints);
00888
00889 cpl_table_erase_column(table, "x");
00890 cpl_table_erase_column(table, "y");
00891
00892 return output;
00893 }
00894
00895
00896
00897
00898
00899
00900
00901 static void mos_extraction(cpl_image *sciwin, cpl_image *skywin,
00902 cpl_image *extracted, cpl_image *sky,
00903 cpl_image *error, int nobjects, int extraction,
00904 double ron, double conad, int ncomb)
00905 {
00906
00907 cpl_vector *vprofile;
00908 cpl_matrix *kernel;
00909 cpl_image *smowin;
00910
00911 int i, j;
00912 int specLen;
00913 int numRows;
00914 int index;
00915 int iter;
00916 int maxIter = 2;
00917 int smoothBox = 31;
00918 double nsigma = 5.0;
00919
00920 double sumWeight, sum, sumSky, sumProf, variance, weight;
00921 double *profile;
00922 double *buffer;
00923 float *edata;
00924 float *ekdata;
00925 float *endata;
00926 float *sdata;
00927 float *kdata;
00928 float *fdata;
00929
00930 double value;
00931
00932
00933 specLen = cpl_image_get_size_x(sciwin);
00934 numRows = cpl_image_get_size_y(sciwin);
00935
00936 edata = cpl_image_get_data(extracted);
00937 edata += nobjects * specLen;
00938
00939 ekdata = cpl_image_get_data(sky);
00940 ekdata += nobjects * specLen;
00941
00942 endata = cpl_image_get_data(error);
00943 endata += nobjects * specLen;
00944
00945 sdata = cpl_image_get_data(sciwin);
00946 kdata = cpl_image_get_data(skywin);
00947
00948
00949
00950
00951
00952
00953
00954 if (extraction && numRows > 5) {
00955 kernel = cpl_matrix_new(3, 3);
00956 cpl_matrix_fill(kernel, 1.0);
00957 smowin = cpl_image_filter_median(sciwin, kernel);
00958 cpl_matrix_delete(kernel);
00959 fdata = cpl_image_get_data(smowin);
00960 for (i = 0; i < specLen; i++)
00961 for (j = 0, edata[i] = 0.0; j < numRows; j++)
00962 edata[i] += fdata[i + j * specLen];
00963 cpl_image_delete(smowin);
00964 }
00965 else {
00966 for (i = 0; i < specLen; i++)
00967 for (j = 0, edata[i] = 0.0; j < numRows; j++)
00968 edata[i] += sdata[i + j * specLen];
00969 }
00970
00971 if (extraction) {
00972
00973 profile = cpl_calloc(specLen * numRows, sizeof(double));
00974 buffer = cpl_calloc(specLen, sizeof(double));
00975
00976 for (iter = 0; iter < maxIter; iter++) {
00977
00978
00979
00980
00981
00982 for (i = 0; i < specLen; i++) {
00983 for (j = 0; j < numRows; j++) {
00984 index = i + j * specLen;
00985
00986 if (fabs(edata[i]) > 0.00001)
00987 profile[index] = sdata[index] / edata[i];
00988 else
00989 profile[index] = 0.0;
00990 }
00991 }
00992
00993 for (j = 0; j < numRows; j++) {
00994
00995
00996
00997
00998
00999 for (i = 0; i < specLen - smoothBox; i++) {
01000 vprofile = cpl_vector_wrap(smoothBox, profile + i + j*specLen);
01001 value = cpl_vector_get_median_const(vprofile);
01002 cpl_vector_unwrap(vprofile);
01003 if (value < 0)
01004 value = 0.0;
01005 buffer[i + smoothBox / 2] = value;
01006 }
01007
01008
01009
01010
01011
01012 vprofile = cpl_vector_wrap(smoothBox / 2, profile + j*specLen);
01013 value = cpl_vector_get_mean(vprofile);
01014 cpl_vector_unwrap(vprofile);
01015
01016 if (value < 0)
01017 value = 0.0;
01018
01019 for (i = 0; i < smoothBox / 2; i++)
01020 buffer[i] = value;
01021
01022 vprofile = cpl_vector_wrap(smoothBox / 2,
01023 profile + specLen - smoothBox/2 + j*specLen);
01024 value = cpl_vector_get_mean(vprofile);
01025 cpl_vector_unwrap(vprofile);
01026
01027 if (value < 0)
01028 value = 0.0;
01029
01030 for (i = 0; i < smoothBox / 2; i++)
01031 buffer[i + specLen - smoothBox / 2] = value;
01032
01033 for (i = 0; i < specLen; i++)
01034 profile[i + j * specLen] = buffer[i];
01035
01036 }
01037
01038
01039
01040
01041
01042 for (i = 0; i < specLen; i++) {
01043 for (j = 0, value = 0.0; j < numRows; j++)
01044 value += profile[i + j * specLen];
01045 if (value > 0.00001)
01046 for (j = 0; j < numRows; j++)
01047 profile[i + j * specLen] /= value;
01048 else
01049 for (j = 0; j < numRows; j++)
01050 profile[i + j * specLen] = 0.0;
01051 }
01052
01053
01054
01055
01056
01057
01058 for (i = 0; i < specLen; i++) {
01059 sum = 0.0;
01060 sumSky = 0.0;
01061 sumWeight = 0.0;
01062 sumProf = 0.0;
01063 for (j = 0; j < numRows; j++) {
01064 index = i + j * specLen;
01065
01066
01067
01068 variance = ron*ron + fabs(edata[i] * profile[index] + kdata[index])
01069 / conad;
01070 variance /= ncomb;
01071 value = sdata[index] - edata[i] * profile[index];
01072 if (fabs(value) / sqrt(variance) < nsigma) {
01073 weight = 1000000 * profile[index] / variance;
01074 sum += weight * sdata[index];
01075 sumSky += weight * kdata[index];
01076 sumWeight += weight * profile[index];
01077 sumProf += profile[index];
01078 }
01079
01080
01081
01082 }
01083
01084 if (sumWeight > 0.00001) {
01085 edata[i] = sum / sumWeight;
01086 ekdata[i] = sumSky / sumWeight;
01087 endata[i] = 1000 * sqrt(sumProf / sumWeight);
01088 }
01089 else {
01090
01091
01092
01093
01094
01095 endata[i] = sqrt(ron*ron + fabs(edata[i] + ekdata[i]) / conad);
01096 }
01097 }
01098 }
01099 cpl_free(profile);
01100 cpl_free(buffer);
01101 }
01102 else {
01103
01104
01105
01106
01107
01108
01109 for (i = 0; i < specLen; i++)
01110 for (j = 0, ekdata[i] = 0.0; j < numRows; j++)
01111 ekdata[i] += kdata[i + j * specLen];
01112
01113
01114
01115
01116
01117 for (i = 0; i < specLen; i++)
01118 endata[i] = sqrt(ron*ron + fabs(edata[i] + ekdata[i]) / conad);
01119
01120 }
01121
01122 }
01123
01124
01171 cpl_table *mos_global_distortion(cpl_table *slits, cpl_table *maskslits,
01172 cpl_table *ids, cpl_table *crv,
01173 double reference)
01174 {
01175 const char *func = "mos_global_distortion";
01176
01177 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01178
01179 cpl_table *global = NULL;
01180 cpl_table *coeff;
01181 cpl_table *dummy;
01182 cpl_vector *ci;
01183 cpl_vector *xmask;
01184 cpl_vector *ymask;
01185 cpl_bivector *mask;
01186 cpl_vector *xccd;
01187 cpl_vector *yccd;
01188 cpl_bivector *ccd;
01189 cpl_polynomial *poly;
01190 double *xtop;
01191 double *ytop;
01192 double *xbottom;
01193 double *ybottom;
01194 double *mxtop;
01195 double *mytop;
01196 double *mxbottom;
01197 double *mybottom;
01198 int *position;
01199 int *length;
01200 int *slit_id;
01201 int *mslit_id;
01202 int nslits, nmaskslits, npoints;
01203 int order;
01204 int i, j;
01205 int minslit = 6;
01206
01207
01208
01209
01210
01211 if (slits == NULL || maskslits == NULL || ids == NULL || crv == NULL) {
01212 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01213 return NULL;
01214 }
01215
01216
01217
01218
01219 nslits = cpl_table_get_nrow(slits);
01220
01221
01222
01223
01224 if (nslits < minslit) {
01225 cpl_msg_warning(func, "Too few slits (%d < %d) for global "
01226 "distortion model determination", nslits, minslit);
01227 return NULL;
01228 }
01229
01230
01231
01232
01233 nmaskslits = cpl_table_get_nrow(maskslits);
01234
01235 length = cpl_table_get_data_int(slits, "length");
01236 position = cpl_table_get_data_int(slits, "position");
01237 slit_id = cpl_table_get_data_int(slits, "slit_id");
01238 mslit_id = cpl_table_get_data_int(maskslits, "slit_id");
01239 xtop = cpl_table_get_data_double(slits, "xtop");
01240 ytop = cpl_table_get_data_double(slits, "ytop");
01241 xbottom = cpl_table_get_data_double(slits, "xbottom");
01242 ybottom = cpl_table_get_data_double(slits, "ybottom");
01243 mxtop = cpl_table_get_data_double(maskslits, "xtop");
01244 mytop = cpl_table_get_data_double(maskslits, "ytop");
01245 mxbottom = cpl_table_get_data_double(maskslits, "xbottom");
01246 mybottom = cpl_table_get_data_double(maskslits, "ybottom");
01247
01248
01249
01250
01251
01252
01253 coeff = cpl_table_new(nslits);
01254 cpl_table_copy_structure(coeff, ids);
01255 cpl_table_new_column(coeff, "xccd", CPL_TYPE_DOUBLE);
01256 cpl_table_new_column(coeff, "yccd", CPL_TYPE_DOUBLE);
01257 cpl_table_new_column(coeff, "xmask", CPL_TYPE_DOUBLE);
01258 cpl_table_new_column(coeff, "ymask", CPL_TYPE_DOUBLE);
01259
01260
01261
01262
01263 for (i = 0; i < nslits; i++) {
01264 for (j = 0; j < nmaskslits; j++) {
01265 if (slit_id[i] == mslit_id[j]) {
01266 cpl_table_set_double(coeff, "xmask", i,
01267 (mxtop[j] + mxbottom[j]) / 2);
01268 cpl_table_set_double(coeff, "ymask", i,
01269 (mytop[j] + mybottom[j]) / 2);
01270 }
01271 }
01272 }
01273
01274 if (cpl_table_has_invalid(coeff, "xmask")) {
01275 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
01276 cpl_table_delete(coeff);
01277 return NULL;
01278 }
01279
01280 for (i = 0; i < nslits; i++) {
01281 cpl_table_set_double(coeff, "xccd", i, (xtop[i] + xbottom[i]) / 2);
01282 cpl_table_set_double(coeff, "yccd", i, (ytop[i] + ybottom[i]) / 2);
01283 }
01284
01285
01286
01287
01288 for (i = 0; i < nslits; i++) {
01289
01290 if (length[i] == 0)
01291 continue;
01292
01293 cpl_table_and_selected_window(ids, position[i], length[i]);
01294 dummy = cpl_table_extract_selected(ids);
01295 for (j = 0; j < 6; j++) {
01296 if (cpl_table_has_column(dummy, clab[j])) {
01297 if (length[i] - cpl_table_count_invalid(dummy, clab[j]) > 10) {
01298 cpl_table_set_double(coeff, clab[j], i,
01299 cpl_table_get_column_median(dummy, clab[j]));
01300 }
01301 }
01302 }
01303
01304 cpl_table_delete(dummy);
01305 cpl_table_select_all(ids);
01306
01307 }
01308
01309
01310
01311
01312 for (j = 0; j < 6; j++) {
01313 if (cpl_table_has_column(coeff, clab[j])) {
01314 cpl_table_and_selected_invalid(coeff, clab[j]);
01315
01316 if (cpl_table_not_selected(coeff))
01317 dummy = cpl_table_extract_selected(coeff);
01318 else
01319 break;
01320
01321 npoints = cpl_table_get_nrow(dummy);
01322
01323 if (npoints >= 6) {
01324
01325 if (npoints >= 12)
01326 order = 2;
01327 else
01328 order = 1;
01329
01330 ci = cpl_vector_wrap(npoints,
01331 cpl_table_get_data_double(dummy, clab[j]));
01332 if (j) {
01333 xccd = cpl_vector_wrap(npoints,
01334 cpl_table_get_data_double(dummy, "xccd"));
01335 yccd = cpl_vector_wrap(npoints,
01336 cpl_table_get_data_double(dummy, "yccd"));
01337 ccd = cpl_bivector_wrap_vectors(xccd, yccd);
01338
01339
01340 poly = cpl_polynomial_fit_2d_create(ccd, ci, order, NULL);
01341
01342 cpl_bivector_unwrap_vectors(ccd);
01343 cpl_vector_unwrap(xccd);
01344 cpl_vector_unwrap(yccd);
01345 cpl_vector_unwrap(ci);
01346 }
01347 else {
01348 xmask = cpl_vector_wrap(npoints,
01349 cpl_table_get_data_double(dummy, "xmask"));
01350 ymask = cpl_vector_wrap(npoints,
01351 cpl_table_get_data_double(dummy, "ymask"));
01352 mask = cpl_bivector_wrap_vectors(xmask, ymask);
01353
01354
01355 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
01356
01357 cpl_bivector_unwrap_vectors(mask);
01358 cpl_vector_unwrap(xmask);
01359 cpl_vector_unwrap(ymask);
01360 cpl_vector_unwrap(ci);
01361 }
01362 }
01363 else {
01364 int p[2] = {0, 0};
01365 poly = cpl_polynomial_new(2);
01366 cpl_polynomial_set_coeff(poly, p,
01367 cpl_table_get_column_median(dummy, clab[j]));
01368 }
01369
01370 cpl_table_delete(dummy);
01371
01372 global = write_global_distortion(global, j, poly);
01373
01374 cpl_polynomial_delete(poly);
01375
01376 cpl_table_select_all(coeff);
01377 }
01378 }
01379
01380
01381
01382
01383 cpl_table_delete(coeff);
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393 cpl_table_set_double(global, "a00", 6, reference);
01394
01395
01396
01397
01398
01399
01400 coeff = cpl_table_duplicate(crv);
01401 cpl_table_new_column(coeff, "xmask", CPL_TYPE_DOUBLE);
01402 cpl_table_new_column(coeff, "ymask", CPL_TYPE_DOUBLE);
01403 slit_id = cpl_table_get_data_int(coeff, "slit_id");
01404 npoints = cpl_table_get_nrow(coeff);
01405
01406
01407
01408
01409 for (i = 0; i < npoints; i++) {
01410 for (j = 0; j < nmaskslits; j++) {
01411 if (slit_id[i] == mslit_id[j]) {
01412 if (i%2) {
01413 cpl_table_set_double(coeff, "xmask", i, mxbottom[j]);
01414 cpl_table_set_double(coeff, "ymask", i, mybottom[j]);
01415 }
01416 else {
01417 cpl_table_set_double(coeff, "xmask", i, mxtop[j]);
01418 cpl_table_set_double(coeff, "ymask", i, mytop[j]);
01419 }
01420 }
01421 }
01422 }
01423
01424
01425
01426
01427 if (cpl_table_has_invalid(coeff, "xmask")) {
01428 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
01429 cpl_table_delete(coeff);
01430 return NULL;
01431 }
01432
01433
01434
01435
01436 for (j = 0; j < 3; j++) {
01437 if (cpl_table_has_column(coeff, clab[j])) {
01438 cpl_table_and_selected_invalid(coeff, clab[j]);
01439
01440 if (cpl_table_not_selected(coeff))
01441 dummy = cpl_table_extract_selected(coeff);
01442 else
01443 break;
01444
01445 npoints = cpl_table_get_nrow(dummy);
01446
01447 if (npoints >= 6) {
01448
01449 if (npoints >= 12)
01450 order = 2;
01451 else
01452 order = 1;
01453
01454 ci = cpl_vector_wrap(npoints,
01455 cpl_table_get_data_double(dummy, clab[j]));
01456 xmask = cpl_vector_wrap(npoints,
01457 cpl_table_get_data_double(dummy, "xmask"));
01458 ymask = cpl_vector_wrap(npoints,
01459 cpl_table_get_data_double(dummy, "ymask"));
01460 mask = cpl_bivector_wrap_vectors(xmask, ymask);
01461
01462 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
01463
01464 cpl_bivector_unwrap_vectors(mask);
01465 cpl_vector_unwrap(ci);
01466 cpl_vector_unwrap(xmask);
01467 cpl_vector_unwrap(ymask);
01468 }
01469 else {
01470 int p[2] = {0, 0};
01471 poly = cpl_polynomial_new(2);
01472 cpl_polynomial_set_coeff(poly, p,
01473 cpl_table_get_column_median(dummy, clab[j]));
01474 }
01475
01476 cpl_table_delete(dummy);
01477
01478 global = write_global_distortion(global, j + 7, poly);
01479
01480 cpl_polynomial_delete(poly);
01481 cpl_table_select_all(coeff);
01482 }
01483 }
01484
01485
01486
01487
01488 cpl_table_delete(coeff);
01489
01490
01491
01492
01493 return global;
01494
01495 }
01496
01497
01535 cpl_table *mos_build_slit_location(cpl_table *global, cpl_table *maskslits,
01536 int ysize)
01537 {
01538 const char *func = "mos_build_slit_location";
01539
01540 cpl_propertylist *sort_col;
01541 cpl_polynomial *ids0;
01542 cpl_polynomial *crv[3];
01543 cpl_polynomial *loc_crv;
01544 cpl_vector *point;
01545 cpl_table *slits;
01546 int nslits;
01547 int *slit_id;
01548 double *dpoint;
01549 double *xtop;
01550 double *ytop;
01551 double *xbottom;
01552 double *ybottom;
01553 double *mxtop;
01554 double *mytop;
01555 double *mxbottom;
01556 double *mybottom;
01557 int i, j;
01558
01559
01560 if (global == NULL || maskslits == NULL) {
01561 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01562 return NULL;
01563 }
01564
01565 nslits = cpl_table_get_nrow(maskslits);
01566 slit_id = cpl_table_get_data_int(maskslits, "slit_id");
01567 mxtop = cpl_table_get_data_double(maskslits, "xtop");
01568 mytop = cpl_table_get_data_double(maskslits, "ytop");
01569 mxbottom = cpl_table_get_data_double(maskslits, "xbottom");
01570 mybottom = cpl_table_get_data_double(maskslits, "ybottom");
01571
01572 slits = cpl_table_duplicate(maskslits);
01573
01574 xtop = cpl_table_get_data_double(slits, "xtop");
01575 ytop = cpl_table_get_data_double(slits, "ytop");
01576 xbottom = cpl_table_get_data_double(slits, "xbottom");
01577 ybottom = cpl_table_get_data_double(slits, "ybottom");
01578
01579 ids0 = read_global_distortion(global, 0);
01580 crv[0] = read_global_distortion(global, 7);
01581 crv[1] = read_global_distortion(global, 8);
01582 crv[2] = read_global_distortion(global, 9);
01583
01584 loc_crv = cpl_polynomial_new(1);
01585
01586 point = cpl_vector_new(2);
01587 dpoint = cpl_vector_get_data(point);
01588
01589 for (i = 0; i < nslits; i++) {
01590 dpoint[0] = mxtop[i];
01591 dpoint[1] = mytop[i];
01592
01593 xtop[i] = cpl_polynomial_eval(ids0, point);
01594
01595 for (j = 0; j < 3; j++)
01596 if (crv[j])
01597 cpl_polynomial_set_coeff(loc_crv, &j,
01598 cpl_polynomial_eval(crv[j], point));
01599
01600 ytop[i] = cpl_polynomial_eval_1d(loc_crv, xtop[i], NULL);
01601
01602 dpoint[0] = mxbottom[i];
01603 dpoint[1] = mybottom[i];
01604 xbottom[i] = cpl_polynomial_eval(ids0, point);
01605
01606 for (j = 0; j < 3; j++)
01607 if (crv[j])
01608 cpl_polynomial_set_coeff(loc_crv, &j,
01609 cpl_polynomial_eval(crv[j], point));
01610
01611 ybottom[i] = cpl_polynomial_eval_1d(loc_crv, xbottom[i], NULL);
01612 }
01613
01614 cpl_vector_delete(point);
01615 cpl_polynomial_delete(ids0);
01616 cpl_polynomial_delete(loc_crv);
01617 for (j = 0; j < 3; j++)
01618 cpl_polynomial_delete(crv[j]);
01619
01620 sort_col = cpl_propertylist_new();
01621 cpl_propertylist_append_bool(sort_col, "ytop", 1);
01622 cpl_table_sort(slits, sort_col);
01623 cpl_table_sort(maskslits, sort_col);
01624 cpl_propertylist_delete(sort_col);
01625
01626
01627
01628
01629
01630 cpl_table_and_selected_double(slits, "ybottom", CPL_GREATER_THAN, ysize-1);
01631 cpl_table_or_selected_double(slits, "ytop", CPL_LESS_THAN, 0);
01632 cpl_table_erase_selected(slits);
01633
01634 nslits = cpl_table_get_nrow(slits);
01635
01636 if (nslits == 0) {
01637 cpl_msg_warning(func, "No slits found on the CCD");
01638 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
01639 cpl_table_delete(slits);
01640 return NULL;
01641 }
01642
01643 if (nslits > 1)
01644 cpl_msg_info(func, "Slit location: %d slits are entirely or partially "
01645 "contained in CCD", nslits);
01646 else
01647 cpl_msg_info(func, "Slit location: %d slit is entirely or partially "
01648 "contained in CCD", nslits);
01649
01650 return slits;
01651
01652 }
01653
01654
01681 cpl_table *mos_build_curv_coeff(cpl_table *global, cpl_table *maskslits,
01682 cpl_table *slits)
01683 {
01684 const char *func = "mos_build_curv_coeff";
01685
01686 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01687
01688
01689 cpl_polynomial *crv[3];
01690 cpl_vector *point;
01691 cpl_table *polytraces;
01692 double *dpoint;
01693 double *xtop;
01694 double *ytop;
01695 double *xbottom;
01696 double *ybottom;
01697 int *slit_id;
01698 int *valid_id;
01699 int nslits, nvalid;
01700 int found;
01701 int i, j, k;
01702
01703
01704 if (global == NULL || slits == NULL || maskslits == NULL) {
01705 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01706 return NULL;
01707 }
01708
01709 nslits = cpl_table_get_nrow(maskslits);
01710 slit_id = cpl_table_get_data_int(maskslits, "slit_id");
01711 xtop = cpl_table_get_data_double(maskslits, "xtop");
01712 ytop = cpl_table_get_data_double(maskslits, "ytop");
01713 xbottom = cpl_table_get_data_double(maskslits, "xbottom");
01714 ybottom = cpl_table_get_data_double(maskslits, "ybottom");
01715
01716 polytraces = cpl_table_new(2*nslits);
01717 cpl_table_new_column(polytraces, "slit_id", CPL_TYPE_INT);
01718 for (i = 0; i < 3; i++)
01719 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
01720
01721 crv[0] = read_global_distortion(global, 7);
01722 crv[1] = read_global_distortion(global, 8);
01723 crv[2] = read_global_distortion(global, 9);
01724
01725 point = cpl_vector_new(2);
01726 dpoint = cpl_vector_get_data(point);
01727
01728 for (i = 0; i < nslits; i++) {
01729 for (j = 0; j < 2; j++) {
01730
01731 cpl_table_set_int(polytraces, "slit_id", 2*i+j, slit_id[i]);
01732
01733 if (j) {
01734 dpoint[0] = xbottom[i];
01735 dpoint[1] = ybottom[i];
01736 }
01737 else {
01738 dpoint[0] = xtop[i];
01739 dpoint[1] = ytop[i];
01740 }
01741
01742 for (k = 0; k < 3; k++)
01743 if (crv[j])
01744 cpl_table_set_double(polytraces, clab[k], 2*i+j,
01745 cpl_polynomial_eval(crv[k], point));
01746 }
01747 }
01748
01749 cpl_vector_delete(point);
01750 for (j = 0; j < 3; j++)
01751 cpl_polynomial_delete(crv[j]);
01752
01753
01754
01755
01756
01757 nvalid = cpl_table_get_nrow(slits);
01758 valid_id = cpl_table_get_data_int(slits, "slit_id");
01759 cpl_table_unselect_all(polytraces);
01760 for (i = 0; i < nslits; i++) {
01761 found = 0;
01762 for (j = 0; j < nvalid; j++) {
01763 if (slit_id[i] == valid_id[j]) {
01764 found = 1;
01765 break;
01766 }
01767 }
01768 if (!found) {
01769 cpl_table_select_row(polytraces, 2*i);
01770 cpl_table_select_row(polytraces, 2*i + 1);
01771 }
01772 }
01773 cpl_table_erase_selected(polytraces);
01774
01775 nslits = cpl_table_get_nrow(polytraces);
01776
01777 if (nslits == 0) {
01778 cpl_msg_warning(func, "No slits found on the CCD");
01779 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
01780 cpl_table_delete(polytraces);
01781 return NULL;
01782 }
01783
01784 if (nslits > 2)
01785 cpl_msg_info(func, "Curvature model: %d slits are entirely or "
01786 "partially contained in CCD", nslits / 2);
01787 else
01788 cpl_msg_info(func, "Curvature model: %d slit is entirely or "
01789 "partially contained in CCD", nslits / 2);
01790
01791 return polytraces;
01792 }
01793
01794
01836 cpl_table *mos_build_disp_coeff(cpl_table *global, cpl_table *slits)
01837 {
01838 const char *func = "mos_build_disp_coeff";
01839
01840 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01841
01842 cpl_polynomial *ids[6];
01843 cpl_vector *point;
01844 cpl_table *idscoeff;
01845 double *dpoint;
01846 double *xtop;
01847 double *ytop;
01848 double *xbottom;
01849 double *ybottom;
01850 int *position;
01851 int *length;
01852 int nslits;
01853 int nrows;
01854 int order;
01855 int ylow, yhig;
01856 int i, j, k;
01857
01858
01859 if (global == NULL || slits == NULL) {
01860 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01861 return NULL;
01862 }
01863
01864 nslits = cpl_table_get_nrow(slits);
01865 position = cpl_table_get_data_int(slits, "position");
01866 length = cpl_table_get_data_int(slits, "length");
01867 xtop = cpl_table_get_data_double(slits, "xtop");
01868 ytop = cpl_table_get_data_double(slits, "ytop");
01869 xbottom = cpl_table_get_data_double(slits, "xbottom");
01870 ybottom = cpl_table_get_data_double(slits, "ybottom");
01871
01872 for (i = 0; i < 6; i++)
01873 ids[i] = read_global_distortion(global, i);
01874
01875 for (i = 0; i < 6; i++)
01876 if (ids[i] == NULL)
01877 break;
01878
01879 order = i - 1;
01880
01881 if (order < 1) {
01882 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
01883 return NULL;
01884 }
01885
01886 nrows = 0;
01887 for (i = 0; i < nslits; i++)
01888 nrows += length[i];
01889
01890 idscoeff = cpl_table_new(nrows);
01891
01892 for (j = 0; j <= order; j++)
01893 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
01894
01895 cpl_table_new_column(idscoeff, "error", CPL_TYPE_DOUBLE);
01896 cpl_table_fill_column_window_double(idscoeff, "error", 0, nrows, 0.0);
01897 cpl_table_new_column(idscoeff, "nlines", CPL_TYPE_INT);
01898 cpl_table_fill_column_window_int(idscoeff, "nlines", 0, nrows, 0);
01899
01900 point = cpl_vector_new(2);
01901 dpoint = cpl_vector_get_data(point);
01902
01903 for (i = 0; i < nslits; i++) {
01904
01905 if (length[i] == 0)
01906 continue;
01907
01908 ylow = position[i];
01909 yhig = ylow + length[i];
01910
01911 for (j = 0; j <= order; j++) {
01912 if (j) {
01913 for (k = 0; k < length[i]; k++) {
01914 dpoint[0] = xbottom[i] + k*(xtop[i]-xbottom[i])/length[i];
01915 dpoint[1] = ybottom[i] + k*(ytop[i]-ybottom[i])/length[i];
01916 cpl_table_set_double(idscoeff, clab[j], ylow + k,
01917 cpl_polynomial_eval(ids[j], point));
01918 }
01919 }
01920 else {
01921 for (k = 0; k < length[i]; k++) {
01922 cpl_table_set_double(idscoeff, clab[0], ylow + k,
01923 xbottom[i] + k*(xtop[i]-xbottom[i])/length[i]);
01924 }
01925 }
01926 }
01927 }
01928
01929 cpl_vector_delete(point);
01930 for (j = 0; j < 6; j++)
01931 cpl_polynomial_delete(ids[j]);
01932
01933 return idscoeff;
01934
01935 }
01936
01937
01960 cpl_image *mos_subtract_sky(cpl_image *science, cpl_table *slits,
01961 cpl_table *polytraces, double reference,
01962 double blue, double red, double dispersion)
01963 {
01964 const char *func = "mos_subtract_sky";
01965
01966 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01967
01968
01969 cpl_image *sky;
01970 cpl_bivector *list;
01971 cpl_vector *listx;
01972 cpl_vector *listy;
01973 cpl_polynomial *polytop;
01974 cpl_polynomial *polybot;
01975 cpl_polynomial *trend;
01976
01977 int *slit_id;
01978 double *dlistx;
01979 double *dlisty;
01980 float *sdata;
01981 float *kdata;
01982 double top, bot;
01983 int itop, ibot;
01984 double coeff;
01985 double ytop, ybot;
01986 double m, q, err;
01987 int npix;
01988
01989 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
01990 int nx, ny;
01991 int nslits;
01992 int *length;
01993 int missing_top, missing_bot;
01994 int order;
01995 int null;
01996 int window = 50;
01997 int count;
01998 int i, j, k;
01999
02000
02001 if (science == NULL || slits == NULL || polytraces == NULL) {
02002 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02003 return NULL;
02004 }
02005
02006 if (dispersion <= 0.0) {
02007 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02008 return NULL;
02009 }
02010
02011 if (red - blue < dispersion) {
02012 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02013 return NULL;
02014 }
02015
02016 nx = cpl_image_get_size_x(science);
02017 ny = cpl_image_get_size_y(science);
02018
02019 sky = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
02020
02021 sdata = cpl_image_get_data(science);
02022 kdata = cpl_image_get_data(sky);
02023
02024 nslits = cpl_table_get_nrow(slits);
02025 order = cpl_table_get_ncol(polytraces) - 2;
02026 length = cpl_table_get_data_int(slits, "length");
02027 slit_id = cpl_table_get_data_int(slits, "slit_id");
02028
02029
02030
02031
02032
02033
02034 pixel_above = (red - reference) / dispersion;
02035 pixel_below = (reference - blue) / dispersion;
02036
02037 for (i = 0; i < nslits; i++) {
02038
02039 if (length[i] == 0)
02040 continue;
02041
02042
02043
02044
02045
02046
02047
02048 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
02049
02050 start_pixel = refpixel - pixel_below;
02051 if (start_pixel < 0)
02052 start_pixel = 0;
02053
02054 end_pixel = refpixel + pixel_above;
02055 if (end_pixel > nx)
02056 end_pixel = nx;
02057
02058 missing_top = 0;
02059 polytop = cpl_polynomial_new(1);
02060 for (k = 0; k <= order; k++) {
02061 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
02062 if (null) {
02063 cpl_polynomial_delete(polytop);
02064 missing_top = 1;
02065 break;
02066 }
02067 cpl_polynomial_set_coeff(polytop, &k, coeff);
02068 }
02069
02070 missing_bot = 0;
02071 polybot = cpl_polynomial_new(1);
02072 for (k = 0; k <= order; k++) {
02073 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
02074 if (null) {
02075 cpl_polynomial_delete(polybot);
02076 missing_bot = 1;
02077 break;
02078 }
02079 cpl_polynomial_set_coeff(polybot, &k, coeff);
02080 }
02081
02082 if (missing_top && missing_bot) {
02083 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
02084 slit_id[i]);
02085 continue;
02086 }
02087
02088
02089
02090
02091
02092
02093
02094 if (missing_top) {
02095 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
02096 "the spectral curvature of the lower edge "
02097 "is used instead.", slit_id[i]);
02098 polytop = cpl_polynomial_duplicate(polybot);
02099 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02100 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02101 k = 0;
02102 coeff = cpl_polynomial_get_coeff(polybot, &k);
02103 coeff += ytop - ybot;
02104 cpl_polynomial_set_coeff(polytop, &k, coeff);
02105 }
02106
02107 if (missing_bot) {
02108 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
02109 "the spectral curvature of the upper edge "
02110 "is used instead.", slit_id[i]);
02111 polybot = cpl_polynomial_duplicate(polytop);
02112 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02113 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02114 k = 0;
02115 coeff = cpl_polynomial_get_coeff(polytop, &k);
02116 coeff -= ytop - ybot;
02117 cpl_polynomial_set_coeff(polybot, &k, coeff);
02118 }
02119
02120
02121
02122
02123
02124
02125 for (j = start_pixel; j < end_pixel; j++) {
02126 top = cpl_polynomial_eval_1d(polytop, j, NULL);
02127 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
02128 itop = floor(top + 0.5) + 1;
02129 ibot = floor(bot + 0.5);
02130 if (itop > ny)
02131 itop = ny;
02132 if (ibot < 0)
02133 ibot = 0;
02134 npix = itop - ibot;
02135 if (npix < 5)
02136 break;
02137
02138 list = cpl_bivector_new(npix);
02139 listx = cpl_bivector_get_x(list);
02140 listy = cpl_bivector_get_y(list);
02141 dlistx = cpl_vector_get_data(listx);
02142 dlisty = cpl_vector_get_data(listy);
02143
02144 for (k = 0; k < npix; k++) {
02145 dlistx[k] = k;
02146 dlisty[k] = sdata[j + (ibot + k)*nx];
02147 }
02148
02149 if (robustLinearFit(list, &q, &m, &err)) {
02150 cpl_bivector_delete(list);
02151 continue;
02152 }
02153
02154 cpl_bivector_delete(list);
02155
02156 for (k = 0; k < npix; k++) {
02157 kdata[j + (ibot + k)*nx] = m*k + q;
02158 }
02159
02160 if (npix > window) {
02161
02162
02163
02164
02165
02166 err = 3*sqrt(err);
02167
02168 count = 0;
02169 for (k = 0; k < npix; k++)
02170 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err)
02171 count++;
02172
02173 if (count < 10)
02174 continue;
02175
02176 list = cpl_bivector_new(count);
02177 listx = cpl_bivector_get_x(list);
02178 listy = cpl_bivector_get_y(list);
02179 dlistx = cpl_vector_get_data(listx);
02180 dlisty = cpl_vector_get_data(listy);
02181
02182 count = 0;
02183 for (k = 0; k < npix; k++) {
02184 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err) {
02185 dlistx[count] = k;
02186 dlisty[count] = sdata[j + (ibot + k)*nx];
02187 count++;
02188 }
02189 }
02190
02191 trend = cpl_polynomial_fit_1d_create(listx, listy, 2, &err);
02192
02193 cpl_bivector_delete(list);
02194
02195 err = 3*sqrt(err);
02196
02197 count = 0;
02198 for (k = 0; k < npix; k++)
02199 if (fabs(sdata[j + (ibot + k)*nx]
02200 - cpl_polynomial_eval_1d(trend, k, NULL)) < err)
02201 count++;
02202
02203 if (count < 10) {
02204 cpl_polynomial_delete(trend);
02205 continue;
02206 }
02207
02208 list = cpl_bivector_new(count);
02209 listx = cpl_bivector_get_x(list);
02210 listy = cpl_bivector_get_y(list);
02211 dlistx = cpl_vector_get_data(listx);
02212 dlisty = cpl_vector_get_data(listy);
02213
02214 count = 0;
02215 for (k = 0; k < npix; k++) {
02216 if (fabs(sdata[j + (ibot + k)*nx]
02217 - cpl_polynomial_eval_1d(trend, k, NULL)) < err) {
02218 dlistx[count] = k;
02219 dlisty[count] = sdata[j + (ibot + k)*nx];
02220 count++;
02221 }
02222 }
02223
02224 cpl_polynomial_delete(trend);
02225
02226 trend = cpl_polynomial_fit_1d_create(listx, listy, 3, &err);
02227
02228 cpl_bivector_delete(list);
02229
02230 for (k = 0; k < npix; k++) {
02231 kdata[j + (ibot + k)*nx] = cpl_polynomial_eval_1d(trend,
02232 k, NULL);
02233 }
02234
02235 cpl_polynomial_delete(trend);
02236 }
02237 }
02238 cpl_polynomial_delete(polytop);
02239 cpl_polynomial_delete(polybot);
02240 }
02241
02242 cpl_image_subtract(science, sky);
02243
02244 return sky;
02245 }
02246
02247
02280 cpl_image *mos_normalise_flat(cpl_image *flat, cpl_image *spatial,
02281 cpl_table *slits, cpl_table *polytraces,
02282 double reference, double blue, double red,
02283 double dispersion, int sradius, int polyorder)
02284 {
02285 const char *func = "mos_normalise_flat";
02286
02287 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
02288
02289
02290 cpl_image *rectified;
02291 cpl_image *smo_flat;
02292 cpl_image *exslit;
02293 cpl_vector *positions;
02294 cpl_vector *flux;
02295 cpl_vector *smo_flux;
02296 cpl_polynomial *trend;
02297 cpl_polynomial *polytop;
02298 cpl_polynomial *polybot;
02299
02300 int *slit_id;
02301 float *p;
02302 float *data;
02303 double *fdata;
02304 double *pdata;
02305 float *sdata;
02306 float *xdata;
02307 float *wdata;
02308 double vtop, vbot, value;
02309 double top, bot;
02310 double coeff;
02311 double ytop, ybot;
02312 double ypos;
02313 double fvalue;
02314 int ivalue;
02315 int yint, yprev;
02316 int npseudo;
02317
02318 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
02319 int nx, ny, nsubx, nsuby;
02320 int xlow, ylow, xhig, yhig;
02321 int nslits;
02322 int *position;
02323 int *length;
02324 int missing_top, missing_bot;
02325 int order;
02326 int npoints;
02327 int uradius;
02328 int null;
02329 int i, j, k;
02330
02331
02332
02333
02334
02335
02336 if (flat == NULL || slits == NULL || polytraces == NULL) {
02337 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02338 return NULL;
02339 }
02340
02341 if (dispersion <= 0.0) {
02342 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02343 return NULL;
02344 }
02345
02346 if (red - blue < dispersion) {
02347 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02348 return NULL;
02349 }
02350
02351 rectified = mos_spatial_calibration(flat, slits, polytraces, reference,
02352 blue, red, dispersion, 0, NULL);
02353
02354 nx = cpl_image_get_size_x(rectified);
02355 ny = cpl_image_get_size_y(rectified);
02356
02357 smo_flat = cpl_image_new(cpl_image_get_size_x(spatial),
02358 cpl_image_get_size_y(spatial), CPL_TYPE_FLOAT);
02359 wdata = cpl_image_get_data(smo_flat);
02360
02361 nslits = cpl_table_get_nrow(slits);
02362 order = cpl_table_get_ncol(polytraces) - 2;
02363 position = cpl_table_get_data_int(slits, "position");
02364 length = cpl_table_get_data_int(slits, "length");
02365 slit_id = cpl_table_get_data_int(slits, "slit_id");
02366
02367
02368
02369
02370
02371
02372 pixel_above = (red - reference) / dispersion;
02373 pixel_below = (reference - blue) / dispersion;
02374
02375 xlow = 1;
02376 xhig = nx;
02377 for (i = 0; i < nslits; i++) {
02378
02379 if (length[i] == 0)
02380 continue;
02381
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392 ylow = position[i] + 1;
02393 yhig = ylow + length[i] - 1;
02394
02395 exslit = cpl_image_extract(rectified, xlow, ylow, xhig, yhig);
02396
02397 if (polyorder < 0) {
02398
02399 cpl_image_turn(exslit, -1);
02400
02401 nsubx = cpl_image_get_size_x(exslit);
02402 nsuby = cpl_image_get_size_y(exslit);
02403 data = cpl_image_get_data(exslit);
02404 flux = cpl_vector_new(nsubx);
02405
02406 uradius = nsubx / 2;
02407 if (uradius > sradius)
02408 uradius = sradius;
02409
02410 for (j = 0; j < nsuby; j++) {
02411 fdata = cpl_vector_get_data(flux);
02412 p = data;
02413 for (k = 0; k < nsubx; k++)
02414 *fdata++ = *p++;
02415 smo_flux = cpl_vector_filter_median_create(flux, uradius);
02416 fdata = cpl_vector_get_data(smo_flux);
02417 p = data;
02418 for (k = 0; k < nsubx; k++)
02419 *p++ = *fdata++;
02420 cpl_vector_delete(smo_flux);
02421 data += nsubx;
02422 }
02423
02424 cpl_vector_delete(flux);
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
02460 cpl_image_turn(exslit, 1);
02461 nsubx = cpl_image_get_size_x(exslit);
02462 nsuby = cpl_image_get_size_y(exslit);
02463 data = cpl_image_get_data(exslit);
02464
02465 for (j = 0; j < nsuby; j++) {
02466 flux = cpl_vector_new(nsubx);
02467 fdata = cpl_vector_get_data(flux);
02468 p = data;
02469 for (k = 0; k < nsubx; k++)
02470 *fdata++ = *p++;
02471 smo_flux = cpl_vector_filter_median_create(flux, sradius);
02472 cpl_vector_delete(flux);
02473 fdata = cpl_vector_get_data(smo_flux);
02474 p = data;
02475 for (k = 0; k < nsubx; k++)
02476 *p++ = *fdata++;
02477 cpl_vector_delete(smo_flux);
02478 data += nsubx;
02479 }
02480 }
02481 else {
02482
02483
02484
02485
02486
02487 nsubx = cpl_image_get_size_x(exslit);
02488 nsuby = cpl_image_get_size_y(exslit);
02489 data = cpl_image_get_data(exslit);
02490
02491 for (j = 0; j < nsuby; j++) {
02492
02493
02494
02495
02496
02497 npoints = 0;
02498 p = data + j*nsubx;
02499 for (k = 0; k < nsubx; k++)
02500 if (p[k] > 1.0)
02501 npoints++;
02502
02503 if (npoints > polyorder + 1) {
02504
02505
02506
02507
02508
02509 flux = cpl_vector_new(npoints);
02510 fdata = cpl_vector_get_data(flux);
02511 positions = cpl_vector_new(npoints);
02512 pdata = cpl_vector_get_data(positions);
02513
02514 npoints = 0;
02515 p = data + j*nsubx;
02516 for (k = 0; k < nsubx; k++) {
02517 if (p[k] > 1.0) {
02518 fdata[npoints] = p[k];
02519 pdata[npoints] = k;
02520 npoints++;
02521 }
02522 }
02523
02524 trend = cpl_polynomial_fit_1d_create(positions, flux,
02525 polyorder, NULL);
02526
02527 cpl_vector_delete(flux);
02528 cpl_vector_delete(positions);
02529
02530 if (trend) {
02531 p = data + j*nsubx;
02532 for (k = 0; k < nsubx; k++)
02533 if (p[k] > 1.0)
02534 p[k] = cpl_polynomial_eval_1d(trend, k, NULL);
02535 cpl_polynomial_delete(trend);
02536 }
02537 else {
02538 cpl_msg_warning(func, "Invalid flat field flux fit "
02539 "(ignored)");
02540 }
02541 }
02542 }
02543 }
02544
02545
02546
02547
02548
02549
02550
02551 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
02552
02553 start_pixel = refpixel - pixel_below;
02554 if (start_pixel < 0)
02555 start_pixel = 0;
02556
02557 end_pixel = refpixel + pixel_above;
02558 if (end_pixel > nx)
02559 end_pixel = nx;
02560
02561 missing_top = 0;
02562 polytop = cpl_polynomial_new(1);
02563 for (k = 0; k <= order; k++) {
02564 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
02565 if (null) {
02566 cpl_polynomial_delete(polytop);
02567 missing_top = 1;
02568 break;
02569 }
02570 cpl_polynomial_set_coeff(polytop, &k, coeff);
02571 }
02572
02573 missing_bot = 0;
02574 polybot = cpl_polynomial_new(1);
02575 for (k = 0; k <= order; k++) {
02576 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
02577 if (null) {
02578 cpl_polynomial_delete(polybot);
02579 missing_bot = 1;
02580 break;
02581 }
02582 cpl_polynomial_set_coeff(polybot, &k, coeff);
02583 }
02584
02585 if (missing_top && missing_bot) {
02586 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
02587 slit_id[i]);
02588 continue;
02589 }
02590
02591
02592
02593
02594
02595
02596
02597 if (missing_top) {
02598 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
02599 "the spectral curvature of the lower edge "
02600 "is used instead.", slit_id[i]);
02601 polytop = cpl_polynomial_duplicate(polybot);
02602 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02603 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02604 k = 0;
02605 coeff = cpl_polynomial_get_coeff(polybot, &k);
02606 coeff += ytop - ybot;
02607 cpl_polynomial_set_coeff(polytop, &k, coeff);
02608 }
02609
02610 if (missing_bot) {
02611 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
02612 "the spectral curvature of the upper edge "
02613 "is used instead.", slit_id[i]);
02614 polybot = cpl_polynomial_duplicate(polytop);
02615 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02616 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02617 k = 0;
02618 coeff = cpl_polynomial_get_coeff(polytop, &k);
02619 coeff -= ytop - ybot;
02620 cpl_polynomial_set_coeff(polybot, &k, coeff);
02621 }
02622
02623
02624
02625
02626
02627
02628
02629
02630
02631 nx = cpl_image_get_size_x(flat);
02632 ny = cpl_image_get_size_y(flat);
02633
02634 sdata = cpl_image_get_data(spatial);
02635 xdata = cpl_image_get_data(exslit);
02636 npseudo = cpl_image_get_size_y(exslit) - 1;
02637
02638
02639
02640
02641
02642 for (j = start_pixel; j < end_pixel; j++) {
02643 top = cpl_polynomial_eval_1d(polytop, j, NULL);
02644 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
02645 for (k = 0; k <= npseudo; k++) {
02646 ypos = top - k*(top-bot)/npseudo;
02647 yint = ypos;
02648
02649
02650
02651
02652
02653
02654
02655
02656 if (yint < 0 || yint >= ny-1) {
02657 yprev = yint;
02658 continue;
02659 }
02660
02661 value = sdata[j + nx*yint];
02662 ivalue = value;
02663 fvalue = value - ivalue;
02664 if (ivalue < npseudo && ivalue >= 0) {
02665 vtop = xdata[j + nx*(npseudo-ivalue)];
02666 vbot = xdata[j + nx*(npseudo-ivalue-1)];
02667 wdata[j + nx*yint] = vtop*(1-fvalue) + vbot*fvalue;
02668
02669 if (k) {
02670
02671
02672
02673
02674
02675
02676
02677 if (yprev - yint > 1) {
02678 value = sdata[j + nx*(yint+1)];
02679 ivalue = value;
02680 fvalue = value - ivalue;
02681 if (ivalue < npseudo && ivalue >= 0) {
02682 vtop = xdata[j + nx*(npseudo-ivalue)];
02683 vbot = xdata[j + nx*(npseudo-ivalue-1)];
02684 wdata[j + nx*(yint+1)] = vtop*(1-fvalue)
02685 + vbot*fvalue;
02686 }
02687 }
02688 }
02689 }
02690 yprev = yint;
02691 }
02692 }
02693 cpl_polynomial_delete(polytop);
02694 cpl_polynomial_delete(polybot);
02695 cpl_image_delete(exslit);
02696 }
02697
02698 cpl_image_delete(rectified);
02699
02700 cpl_image_divide(flat, smo_flat);
02701
02702 return smo_flat;
02703 }
02704
02705
02730 cpl_image *mos_normalise_longflat(cpl_image *flat, int sradius, int dradius,
02731 int polyorder)
02732 {
02733 const char *func = "mos_normalise_longflat";
02734
02735 cpl_image *smo_flat;
02736 cpl_image *profile;
02737 cpl_vector *flux;
02738 cpl_vector *smo_flux;
02739 cpl_vector *positions;
02740 cpl_polynomial *trend;
02741
02742 float *level;
02743 float *p;
02744 float *data;
02745 double *fdata;
02746 double *pdata;
02747
02748 int nx, ny;
02749 int npoints;
02750 int i, j;
02751
02752
02753 if (flat == NULL) {
02754 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02755 return NULL;
02756 }
02757
02758 if (sradius < 1 || dradius < 1) {
02759 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02760 return NULL;
02761 }
02762
02763 smo_flat = cpl_image_duplicate(flat);
02764
02765 if (polyorder < 0) {
02766
02767
02768
02769
02770
02771 cpl_image_turn(smo_flat, -1);
02772
02773 nx = cpl_image_get_size_x(smo_flat);
02774 ny = cpl_image_get_size_y(smo_flat);
02775 data = cpl_image_get_data(smo_flat);
02776
02777 for (i = 0; i < ny; i++) {
02778 flux = cpl_vector_new(nx);
02779 fdata = cpl_vector_get_data(flux);
02780 p = data;
02781 for (j = 0; j < nx; j++)
02782 *fdata++ = *p++;
02783 smo_flux = cpl_vector_filter_median_create(flux, sradius);
02784 cpl_vector_delete(flux);
02785 fdata = cpl_vector_get_data(smo_flux);
02786 p = data;
02787 for (j = 0; j < nx; j++)
02788 *p++ = *fdata++;
02789 cpl_vector_delete(smo_flux);
02790 data += nx;
02791 }
02792
02793
02794
02795
02796
02797 cpl_image_turn(smo_flat, 1);
02798
02799 nx = cpl_image_get_size_x(smo_flat);
02800 ny = cpl_image_get_size_y(smo_flat);
02801 data = cpl_image_get_data(smo_flat);
02802
02803 for (i = 0; i < ny; i++) {
02804 flux = cpl_vector_new(nx);
02805 fdata = cpl_vector_get_data(flux);
02806 p = data;
02807 for (j = 0; j < nx; j++)
02808 *fdata++ = *p++;
02809 smo_flux = cpl_vector_filter_median_create(flux, sradius);
02810 cpl_vector_delete(flux);
02811 fdata = cpl_vector_get_data(smo_flux);
02812 p = data;
02813 for (j = 0; j < nx; j++)
02814 *p++ = *fdata++;
02815 cpl_vector_delete(smo_flux);
02816 data += nx;
02817 }
02818 }
02819 else {
02820
02821
02822
02823
02824
02825 cpl_image_turn(smo_flat, -1);
02826
02827 nx = cpl_image_get_size_x(smo_flat);
02828 ny = cpl_image_get_size_y(smo_flat);
02829 data = cpl_image_get_data(smo_flat);
02830
02831 profile = cpl_image_collapse_median_create(smo_flat, 1, 0, 0);
02832 level = cpl_image_get_data(profile);
02833
02834 for (i = 0; i < ny; i++) {
02835
02836
02837
02838
02839
02840
02841
02842 npoints = 0;
02843 p = data + i*nx;
02844 for (j = 0; j < nx; j++)
02845 if (fabs(p[j]/level[i] - 1) < 0.20)
02846 npoints++;
02847
02848 if (npoints > polyorder + 1) {
02849
02850
02851
02852
02853
02854 flux = cpl_vector_new(npoints);
02855 fdata = cpl_vector_get_data(flux);
02856 positions = cpl_vector_new(npoints);
02857 pdata = cpl_vector_get_data(positions);
02858
02859 npoints = 0;
02860 p = data + i*nx;
02861 for (j = 0; j < nx; j++) {
02862 if (fabs(p[j]/level[i] - 1) < 0.20) {
02863 fdata[npoints] = p[j];
02864 pdata[npoints] = j;
02865 npoints++;
02866 }
02867 }
02868
02869 trend = cpl_polynomial_fit_1d_create(positions, flux,
02870 polyorder, NULL);
02871
02872 cpl_vector_delete(flux);
02873 cpl_vector_delete(positions);
02874
02875 if (trend) {
02876 p = data + i*nx;
02877 for (j = 0; j < nx; j++)
02878 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
02879 cpl_polynomial_delete(trend);
02880 }
02881 else {
02882 cpl_msg_warning(func,
02883 "Invalid flat field flux fit (ignored)");
02884 }
02885 }
02886 }
02887
02888 cpl_image_delete(profile);
02889 cpl_image_turn(smo_flat, 1);
02890
02891 }
02892
02893 cpl_image_divide(flat, smo_flat);
02894
02895 return smo_flat;
02896 }
02897
02898
02923 cpl_error_code mos_interpolate_wavecalib(cpl_table *idscoeff,
02924 cpl_image *wavemap, int mode)
02925 {
02926 const char *func = "mos_interpolate_wavecalib";
02927
02928 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
02929
02930
02931 cpl_vector *wave;
02932 cpl_vector *positions;
02933 cpl_polynomial *trend;
02934
02935 float *p;
02936 float *data;
02937 double *wdata;
02938 double *pdata;
02939
02940 double c;
02941 double mse, ksigma;
02942
02943 int order;
02944 int nrows, first_row, last_row;
02945 int nx, ny;
02946 int npoints, rpoints;
02947 int null;
02948 int i, j, k;
02949
02950 int polyorder = 4;
02951
02952
02953 if (idscoeff == NULL)
02954 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02955
02956 if (mode < 0 || mode > 2)
02957 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02958
02959 if (mode == 0)
02960 return CPL_ERROR_NONE;
02961
02962 if (wavemap) {
02963
02964
02965
02966
02967
02968 cpl_image_turn(wavemap, -1);
02969
02970 nx = cpl_image_get_size_x(wavemap);
02971 ny = cpl_image_get_size_y(wavemap);
02972 data = cpl_image_get_data(wavemap);
02973
02974 for (i = 0; i < ny; i++) {
02975
02976
02977
02978
02979
02980
02981 npoints = 0;
02982 p = data + i*nx;
02983 for (j = 0; j < nx; j++)
02984 if (p[j] > 1.0)
02985 npoints++;
02986
02987 if (npoints > polyorder + 1) {
02988
02989
02990
02991
02992
02993 wave = cpl_vector_new(npoints);
02994 wdata = cpl_vector_get_data(wave);
02995 positions = cpl_vector_new(npoints);
02996 pdata = cpl_vector_get_data(positions);
02997
02998 npoints = 0;
02999 p = data + i*nx;
03000 for (j = 0; j < nx; j++) {
03001 if (p[j] > 1.0) {
03002 wdata[npoints] = p[j];
03003 pdata[npoints] = j;
03004 npoints++;
03005 }
03006 }
03007
03008 trend = cpl_polynomial_fit_1d_create(positions, wave,
03009 polyorder, &mse);
03010
03011 ksigma = 3*sqrt(mse);
03012
03013 cpl_vector_delete(wave);
03014 cpl_vector_delete(positions);
03015
03016 if (trend) {
03017
03018
03019
03020
03021
03022 rpoints = 0;
03023 p = data + i*nx;
03024 for (j = 0; j < nx; j++)
03025 if (p[j] > 1.0)
03026 if (fabs(cpl_polynomial_eval_1d(trend, j, NULL)
03027 - p[j]) < ksigma)
03028 rpoints++;
03029
03030 if (rpoints < npoints && rpoints > polyorder + 1) {
03031
03032 wave = cpl_vector_new(rpoints);
03033 wdata = cpl_vector_get_data(wave);
03034 positions = cpl_vector_new(rpoints);
03035 pdata = cpl_vector_get_data(positions);
03036
03037 npoints = 0;
03038 p = data + i*nx;
03039 for (j = 0; j < nx; j++) {
03040 if (p[j] > 1.0) {
03041 if (fabs(cpl_polynomial_eval_1d(trend,
03042 j, NULL) - p[j])
03043 < ksigma) {
03044 wdata[npoints] = p[j];
03045 pdata[npoints] = j;
03046 npoints++;
03047 }
03048 }
03049 }
03050
03051 cpl_polynomial_delete(trend);
03052 trend = cpl_polynomial_fit_1d_create(positions, wave,
03053 polyorder, NULL);
03054
03055 cpl_vector_delete(wave);
03056 cpl_vector_delete(positions);
03057 }
03058 }
03059
03060 if (trend) {
03061 p = data + i*nx;
03062 if (mode == 1) {
03063 for (j = 0; j < nx; j++)
03064 if (p[j] < 1.0)
03065 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
03066 }
03067 else if (mode == 2) {
03068 for (j = 0; j < nx; j++)
03069 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
03070 }
03071 cpl_polynomial_delete(trend);
03072 }
03073 else {
03074 cpl_msg_warning(func,
03075 "Invalid wavelength field fit (ignored)");
03076 }
03077 }
03078
03079 }
03080
03081 cpl_image_turn(wavemap, 1);
03082
03083 }
03084
03085
03086
03087
03088
03089
03090 nrows = cpl_table_get_nrow(idscoeff);
03091
03092 order = 0;
03093 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
03094 ++order;
03095 --order;
03096
03097 first_row = 0;
03098 while (!cpl_table_is_valid(idscoeff, clab[0], first_row))
03099 first_row++;
03100
03101 last_row = nrows - 1;
03102 while (!cpl_table_is_valid(idscoeff, clab[0], last_row))
03103 last_row--;
03104
03105 for (k = 0; k <= order; k++) {
03106
03107 npoints = nrows - cpl_table_count_invalid(idscoeff, clab[k]);
03108 wave = cpl_vector_new(npoints);
03109 wdata = cpl_vector_get_data(wave);
03110 positions = cpl_vector_new(npoints);
03111 pdata = cpl_vector_get_data(positions);
03112
03113 npoints = 0;
03114 for (i = first_row; i <= last_row; i++) {
03115 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
03116 if (null == 0) {
03117 wdata[npoints] = c;
03118 pdata[npoints] = i;
03119 npoints++;
03120 }
03121 }
03122
03123 trend = cpl_polynomial_fit_1d_create(positions, wave, 2, &mse);
03124
03125 ksigma = 3*sqrt(mse);
03126
03127 cpl_vector_delete(wave);
03128 cpl_vector_delete(positions);
03129
03130
03131
03132
03133
03134 if (trend) {
03135 rpoints = 0;
03136 for (i = first_row; i <= last_row; i++) {
03137 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
03138 if (null == 0) {
03139 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
03140 < ksigma) {
03141 rpoints++;
03142 }
03143 }
03144 }
03145
03146 if (rpoints > 0 && rpoints < npoints) {
03147 cpl_msg_debug(func, "%d points rejected from "
03148 "wavelength calibration fit",
03149 npoints - rpoints);
03150
03151 wave = cpl_vector_new(rpoints);
03152 wdata = cpl_vector_get_data(wave);
03153 positions = cpl_vector_new(rpoints);
03154 pdata = cpl_vector_get_data(positions);
03155
03156 npoints = 0;
03157 for (i = first_row; i <= last_row; i++) {
03158 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
03159 if (null == 0) {
03160 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
03161 < ksigma) {
03162 wdata[npoints] = c;
03163 pdata[npoints] = i;
03164 npoints++;
03165 }
03166 }
03167 }
03168
03169 if (npoints) {
03170 cpl_polynomial_delete(trend);
03171 trend = cpl_polynomial_fit_1d_create(positions,
03172 wave, 2, NULL);
03173 }
03174
03175 cpl_vector_delete(wave);
03176 cpl_vector_delete(positions);
03177
03178 }
03179 }
03180
03181 if (trend) {
03182 for (i = first_row; i <= last_row; i++) {
03183 if (mode == 1) {
03184 if (!cpl_table_is_valid(idscoeff, clab[k], i)) {
03185 cpl_table_set_double(idscoeff, clab[k], i,
03186 cpl_polynomial_eval_1d(trend, i,
03187 NULL));
03188 }
03189 }
03190 else if (mode == 2) {
03191 cpl_table_set_double(idscoeff, clab[k], i,
03192 cpl_polynomial_eval_1d(trend, i, NULL));
03193 }
03194 }
03195 cpl_polynomial_delete(trend);
03196 }
03197 else {
03198 cpl_msg_warning(func, "Invalid IDS coefficient fit (ignored)");
03199 }
03200
03201 }
03202
03203 return CPL_ERROR_NONE;
03204 }
03205
03206
03207
03233 cpl_image *mos_remove_bias(cpl_image *image, cpl_image *bias,
03234 cpl_table *overscans)
03235 {
03236 const char *func = "mos_remove_bias";
03237
03238 cpl_image *unbiased;
03239 cpl_image *overscan;
03240 double mean_bias_level;
03241 double mean_overscans_level;
03242 int count;
03243 int nrows;
03244 int xlow, ylow, xhig, yhig;
03245 int i;
03246
03247
03248 if (image == NULL || overscans == NULL) {
03249 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03250 return NULL;
03251 }
03252
03253 nrows = cpl_table_get_nrow(overscans);
03254
03255 if (nrows == 0) {
03256 cpl_msg_error(func, "Empty overscan table");
03257 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
03258 return NULL;
03259 }
03260
03261 if (bias) {
03262 if (nrows == 1) {
03263 unbiased = cpl_image_subtract_create(image, bias);
03264 if (unbiased == NULL) {
03265 cpl_msg_error(func, "Incompatible master bias");
03266 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03267 }
03268 return unbiased;
03269 }
03270 mean_bias_level = cpl_image_get_mean(bias);
03271 }
03272 else {
03273 if (nrows == 1) {
03274 cpl_msg_error(func, "No master bias in input, and no overscan "
03275 "regions in input image: bias subtraction "
03276 "cannot be performed!");
03277 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
03278 return NULL;
03279 }
03280 mean_bias_level = 0.0;
03281 }
03282
03283 mean_overscans_level = 0.0;
03284 count = 0;
03285 for (i = 0; i < nrows; i++) {
03286 xlow = cpl_table_get_int(overscans, "xlow", i, NULL);
03287 ylow = cpl_table_get_int(overscans, "ylow", i, NULL);
03288 xhig = cpl_table_get_int(overscans, "xhig", i, NULL);
03289 yhig = cpl_table_get_int(overscans, "yhig", i, NULL);
03290
03291 if (i == 0) {
03292 unbiased = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
03293 if (unbiased == NULL) {
03294 cpl_msg_error(func, "Incompatible overscan table");
03295 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03296 return NULL;
03297 }
03298 if (bias) {
03299 if (cpl_image_subtract(unbiased, bias)) {
03300 cpl_msg_error(func, "Incompatible master bias");
03301 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03302 cpl_image_delete(unbiased);
03303 return NULL;
03304 }
03305 }
03306 }
03307 else {
03308 overscan = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
03309 if (overscan == NULL) {
03310 cpl_msg_error(func, "Incompatible overscan table");
03311 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03312 cpl_image_delete(unbiased);
03313 return NULL;
03314 }
03315
03316 mean_overscans_level += cpl_image_get_median(overscan);
03317 count++;
03318
03319
03320
03321
03322
03323
03324
03325
03326 cpl_image_delete(overscan);
03327 }
03328 }
03329
03330
03331
03332
03333
03334 mean_overscans_level /= count;
03335
03336 cpl_image_subtract_scalar(unbiased, mean_overscans_level - mean_bias_level);
03337
03338 return unbiased;
03339
03340 }
03341
03342
03401 cpl_error_code mos_arc_background_1D(float *spectrum, float *back,
03402 int length, int msize, int fsize)
03403 {
03404 const char *func = "mos_arc_background_1D";
03405
03406 float *minf;
03407 float *maxf;
03408 float *smof;
03409 int i;
03410
03411
03412 if (spectrum == NULL || back == NULL)
03413 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03414
03415 if (msize % 2 == 0)
03416 msize++;
03417
03418 if (fsize % 2 == 0)
03419 fsize++;
03420
03421 if (msize < 3 || fsize < msize || length < 2*fsize)
03422 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
03423
03424
03425 minf = min_filter(spectrum, length, msize);
03426 smof = smo_filter(minf, length, fsize);
03427 cpl_free(minf);
03428 maxf = max_filter(smof, length, 2*msize+1);
03429 cpl_free(smof);
03430 smof = smo_filter(maxf, length, 2*fsize+1);
03431 cpl_free(maxf);
03432 minf = min_filter(smof, length, 2*msize+1);
03433 cpl_free(smof);
03434 smof = smo_filter(minf, length, 2*fsize+1);
03435 cpl_free(minf);
03436
03437 for (i = 0; i < length; i++)
03438 back[i] = smof[i];
03439
03440 cpl_free(smof);
03441
03442 return CPL_ERROR_NONE;
03443
03444 }
03445
03446
03503 cpl_image *mos_arc_background(cpl_image *image, int msize, int fsize)
03504 {
03505 const char *func = "mos_arc_background";
03506
03507 cpl_image *fimage;
03508 cpl_image *bimage;
03509 cpl_matrix *kernel;
03510 float *data;
03511 float *bdata;
03512 float *row;
03513 float *brow;
03514 int nx, ny;
03515 int i;
03516
03517
03518 if (image == NULL) {
03519 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03520 return NULL;
03521 }
03522
03523 if (msize % 2 == 0)
03524 msize++;
03525
03526 if (fsize % 2 == 0)
03527 fsize++;
03528
03529 nx = cpl_image_get_size_x(image);
03530 ny = cpl_image_get_size_y(image);
03531
03532 bimage = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
03533
03534 kernel = cpl_matrix_new(3, 3);
03535 cpl_matrix_fill(kernel, 1.0);
03536 fimage = cpl_image_filter_median(image, kernel);
03537 cpl_matrix_delete(kernel);
03538
03539 data = cpl_image_get_data_float(fimage);
03540 bdata = cpl_image_get_data_float(bimage);
03541
03542 for (i = 0; i < ny; i++) {
03543 row = data + i * nx;
03544 brow = bdata + i * nx;
03545 if (mos_arc_background_1D(row, brow, nx, msize, fsize)) {
03546 cpl_error_set_where(func);
03547 cpl_image_delete(fimage);
03548 cpl_image_delete(bimage);
03549 return NULL;
03550 }
03551 }
03552
03553 cpl_image_delete(fimage);
03554
03555 return bimage;
03556 }
03557
03558
03579 int mos_lines_width(const float *spectrum, int length)
03580 {
03581
03582 const char *func = "mos_lines_width";
03583
03584 double *profile1 = cpl_calloc(length - 1, sizeof(double));
03585 double *profile2 = cpl_calloc(length - 1, sizeof(double));
03586
03587 double norm, value, max;
03588 int radius = 20;
03589 int short_length = length - 2*radius - 1;
03590 int width;
03591 int i, j, k;
03592
03593
03594
03595
03596
03597
03598 for (j = 0, i = 1; i < length; j++, i++) {
03599 profile1[j] = profile2[j] = spectrum[i] - spectrum[j];
03600 if (profile1[j] < 0)
03601 profile1[j] = 0;
03602 if (profile2[j] > 0)
03603 profile2[j] = 0;
03604 else
03605 profile2[j] = -profile2[j];
03606 }
03607
03608
03609
03610
03611
03612
03613 length--;
03614
03615 norm = 0;
03616 for (i = 0; i < length; i++)
03617 if (norm < profile1[i])
03618 norm = profile1[i];
03619
03620 for (i = 0; i < length; i++) {
03621 profile1[i] /= norm;
03622 profile2[i] /= norm;
03623 }
03624
03625
03626
03627
03628
03629
03630 max = -1;
03631 for (i = 0; i <= radius; i++) {
03632 value = 0;
03633 for (j = 0; j < short_length; j++) {
03634 k = radius+j;
03635 value += profile1[k] * profile2[k+i];
03636 }
03637 if (max < value) {
03638 max = value;
03639 width = i;
03640 }
03641 }
03642
03643 cpl_free(profile1);
03644 cpl_free(profile2);
03645
03646 if (max < 0.0) {
03647 cpl_msg_debug(func, "Cannot estimate line width");
03648 width = 1;
03649 }
03650
03651 return width;
03652
03653 }
03654
03655
03682 cpl_vector *mos_peak_candidates(const float *spectrum,
03683 int length, float level,
03684 float exp_width)
03685 {
03686
03687 const char *func = "mos_peak_candidates";
03688
03689 int i, j;
03690 int nint = length - 1;
03691 int n = 0;
03692 int width = 2 * ceil(exp_width / 2) + 1;
03693 int start = width / 2;
03694 int end = length - width / 2;
03695 int step;
03696 float *smo;
03697 double *data = cpl_calloc(length/2, sizeof(double));
03698
03699
03700 if (spectrum == NULL) {
03701 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03702 return NULL;
03703 }
03704
03705
03706
03707
03708
03709
03710
03711 if (width > 7) {
03712 smo = cpl_calloc(length, sizeof(float));
03713 start = width / 2;
03714 end = length - width / 2;
03715 for (i = 0; i < start; i++)
03716 smo[i] = spectrum[i];
03717 for (i = start; i < end; i++) {
03718 for (j = i - start; j <= i + start; j++)
03719 smo[i] += spectrum[j];
03720 smo[i] /= width;
03721 }
03722 for (i = end; i < length; i++)
03723 smo[i] = spectrum[i];
03724 }
03725 else {
03726 smo = (float *)spectrum;
03727 }
03728
03729
03730
03731
03732
03733
03734 if (width > 20)
03735 step = width / 2;
03736 else
03737 step = 1;
03738
03739 for (i = step; i < nint - step + 1; i += step) {
03740 if (smo[i] > level) {
03741 if (smo[i] >= smo[i-step] && smo[i] > smo[i+step]) {
03742 if (smo[i-step] != 0.0 && smo[i+step] != 0.0) {
03743 data[n] = i + step * values_to_dx(smo[i-step], smo[i], smo[i+step]);
03744 ++n;
03745 }
03746 }
03747 }
03748 }
03749
03750 if (width > 7) {
03751 cpl_free(smo);
03752 }
03753
03754 if (n == 0) {
03755 cpl_free(data);
03756 return NULL;
03757 }
03758
03759 return cpl_vector_wrap(n, data);
03760
03761 }
03762
03763
03785 cpl_vector *mos_refine_peaks(const float *spectrum, int length,
03786 cpl_vector *peaks, int sradius)
03787 {
03788
03789 const char *func = "mos_refine_peaks";
03790
03791 double *data;
03792 float pos;
03793 int npeaks;
03794 int startPos, endPos;
03795 int window = 2*sradius+1;
03796 int i, j;
03797
03798
03799 if (peaks == NULL || spectrum == NULL) {
03800 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03801 return NULL;
03802 }
03803
03804 npeaks = cpl_vector_get_size(peaks);
03805 data = cpl_vector_unwrap(peaks);
03806
03807 for (i = 0; i < npeaks; i++) {
03808 startPos = data[i] - window/2;
03809 endPos = startPos + window;
03810 if (startPos < 0 || endPos >= length)
03811 continue;
03812
03813 if (0 == peakPosition(spectrum + startPos, window, &pos, 1)) {
03814 pos += startPos;
03815 data[i] = pos;
03816 }
03817 }
03818
03819 for (i = 1; i < npeaks; i++)
03820 if (data[i] - data[i-1] < 0.5)
03821 data[i-1] = -1.0;
03822
03823 for (i = 0, j = 0; i < npeaks; i++) {
03824 if (data[i] > 0.0) {
03825 if (i != j)
03826 data[j] = data[i];
03827 j++;
03828 }
03829 }
03830
03831 return cpl_vector_wrap(j, data);
03832
03833 }
03834
03835
03889 cpl_bivector *mos_identify_peaks(cpl_vector *peaks, cpl_vector *lines,
03890 double min_disp, double max_disp,
03891 double tolerance)
03892 {
03893
03894 int i, j, k, l;
03895 int nlint, npint;
03896 int minpos;
03897 float min;
03898 double lratio, pratio;
03899 double lo_start, lo_end, hi_start, hi_end, denom;
03900 double disp, variation, prev_variation;
03901 int max, maxpos, minl, mink;
03902 int ambiguous;
03903 int npeaks_lo, npeaks_hi;
03904 int *peak_lo;
03905 int *peak_hi;
03906 int **ident;
03907 int *nident;
03908 int *lident;
03909
03910 double *peak;
03911 double *line;
03912 int npeaks, nlines;
03913
03914 double *xpos;
03915 double *lambda;
03916 int *ilambda;
03917 double *tmp_xpos;
03918 double *tmp_lambda;
03919 int *tmp_ilambda;
03920 int *flag;
03921 int n = 0;
03922 int nn;
03923 int nseq = 0;
03924 int gap;
03925 int *seq_length;
03926 int found;
03927
03928 peak = cpl_vector_get_data(peaks);
03929 npeaks = cpl_vector_get_size(peaks);
03930 line = cpl_vector_get_data(lines);
03931 nlines = cpl_vector_get_size(lines);
03932
03933 if (npeaks < 4)
03934 return NULL;
03935
03936 peak_lo = cpl_malloc(npeaks * sizeof(int));
03937 peak_hi = cpl_malloc(npeaks * sizeof(int));
03938 nident = cpl_calloc(npeaks, sizeof(int));
03939 lident = cpl_calloc(nlines, sizeof(int));
03940 xpos = cpl_calloc(npeaks, sizeof(double));
03941 lambda = cpl_calloc(npeaks, sizeof(double));
03942 ilambda = cpl_calloc(npeaks, sizeof(int));
03943 tmp_xpos = cpl_calloc(npeaks, sizeof(double));
03944 tmp_lambda = cpl_calloc(npeaks, sizeof(double));
03945 tmp_ilambda = cpl_calloc(npeaks, sizeof(int));
03946 flag = cpl_calloc(npeaks, sizeof(int));
03947 seq_length = cpl_calloc(npeaks, sizeof(int));
03948 ident = cpl_malloc(npeaks * sizeof(int *));
03949 for (i = 0; i < npeaks; i++)
03950 ident[i] = cpl_malloc(3 * npeaks * sizeof(int));
03951
03952
03953
03954
03955
03956
03957 nlint = nlines - 1;
03958 npint = npeaks - 1;
03959
03960
03961
03962
03963
03964
03965 for (i = 1; i < nlint; i++) {
03966
03967
03968
03969
03970
03971
03972
03973
03974
03975 lratio = (line[i+1] - line[i]) / (line[i] - line[i-1]);
03976
03977
03978
03979
03980
03981
03982 for (j = 1; j < npint; j++) {
03983
03984
03985
03986
03987
03988
03989
03990
03991
03992
03993
03994
03995 lo_start = peak[j] - (line[i] - line[i-1]) / min_disp;
03996 lo_end = peak[j] - (line[i] - line[i-1]) / max_disp;
03997 hi_start = peak[j] + (line[i+1] - line[i]) / max_disp;
03998 hi_end = peak[j] + (line[i+1] - line[i]) / min_disp;
03999
04000 for (npeaks_lo = 0, k = 0; k < npeaks; k++) {
04001 if (peak[k] > lo_end)
04002 break;
04003 if (peak[k] > lo_start) {
04004 peak_lo[npeaks_lo] = k;
04005 ++npeaks_lo;
04006 }
04007 }
04008
04009 if (npeaks_lo == 0)
04010 continue;
04011
04012 for (npeaks_hi = 0, k = 0; k < npeaks; k++) {
04013 if (peak[k] > hi_end)
04014 break;
04015 if (peak[k] > hi_start) {
04016 peak_hi[npeaks_hi] = k;
04017 ++npeaks_hi;
04018 }
04019 }
04020
04021 if (npeaks_hi == 0)
04022 continue;
04023
04024
04025
04026
04027
04028
04029
04030
04031
04032
04033 prev_variation = 1000.0;
04034 minl = mink = 0;
04035
04036 for (k = 0; k < npeaks_lo; k++) {
04037 denom = peak[j] - peak[peak_lo[k]];
04038 for (l = 0; l < npeaks_hi; l++) {
04039
04040
04041
04042
04043
04044
04045
04046 pratio = (peak[peak_hi[l]] - peak[j]) / denom;
04047
04048
04049
04050
04051
04052
04053
04054
04055
04056
04057
04058
04059 variation = fabs(lratio-pratio) / pratio;
04060
04061 if (variation < tolerance) {
04062 if (variation < prev_variation) {
04063 prev_variation = variation;
04064 minl = l;
04065 mink = k;
04066 }
04067 }
04068 }
04069 }
04070 if (prev_variation < tolerance) {
04071 ident[j][nident[j]] = i;
04072 ident[peak_hi[minl]][nident[peak_hi[minl]]] = i + 1;
04073 ident[peak_lo[mink]][nident[peak_lo[mink]]] = i - 1;
04074 ++nident[j];
04075 ++nident[peak_hi[minl]];
04076 ++nident[peak_lo[mink]];
04077 }
04078 }
04079 }
04080
04081
04082
04083
04084
04085
04086
04087
04088 for (i = 0; i < npeaks; i++) {
04089
04090
04091
04092
04093
04094
04095
04096
04097 if (nident[i] > 1) {
04098
04099
04100
04101
04102
04103
04104 for (j = 0; j < nlines; j++)
04105 lident[j] = 0;
04106
04107
04108
04109
04110
04111
04112
04113 for (j = 0; j < nident[i]; j++)
04114 ++lident[ident[i][j]];
04115
04116
04117
04118
04119
04120
04121 max = 0;
04122 maxpos = 0;
04123 for (j = 0; j < nlines; j++) {
04124 if (max < lident[j]) {
04125 max = lident[j];
04126 maxpos = j;
04127 }
04128 }
04129
04130
04131
04132
04133
04134
04135
04136
04137 ambiguous = 0;
04138
04139 for (k = maxpos + 1; k < nlines; k++) {
04140 if (lident[k] == max) {
04141 ambiguous = 1;
04142 break;
04143 }
04144 }
04145
04146 if (ambiguous)
04147 continue;
04148
04149
04150
04151
04152
04153
04154
04155 tmp_xpos[n] = peak[i];
04156 tmp_lambda[n] = line[maxpos];
04157 tmp_ilambda[n] = maxpos;
04158
04159 ++n;
04160
04161 }
04162
04163 }
04164
04165
04166
04167
04168
04169
04170
04171
04172
04173
04174
04175
04176
04177
04178 if (n > 1) {
04179 nn = 0;
04180 nseq = 0;
04181 for (k = 0; k < n; k++) {
04182 if (flag[k] == 0) {
04183 flag[k] = 1;
04184 xpos[nn] = tmp_xpos[k];
04185 lambda[nn] = tmp_lambda[k];
04186 ilambda[nn] = tmp_ilambda[k];
04187 ++seq_length[nseq];
04188 ++nn;
04189
04190
04191
04192
04193
04194
04195
04196 i = k;
04197 while (i < n - 1) {
04198 found = 0;
04199 for (j = i + 1; j < n; j++) {
04200 if (flag[j] == 0) {
04201 disp = (tmp_lambda[j] - tmp_lambda[i])
04202 / (tmp_xpos[j] - tmp_xpos[i]);
04203 if (disp >= min_disp && disp <= max_disp) {
04204 flag[j] = 1;
04205 xpos[nn] = tmp_xpos[j];
04206 lambda[nn] = tmp_lambda[j];
04207 ilambda[nn] = tmp_ilambda[j];
04208 ++seq_length[nseq];
04209 ++nn;
04210 i = j;
04211 found = 1;
04212 break;
04213 }
04214 }
04215 }
04216 if (!found)
04217 break;
04218 }
04219
04220
04221
04222
04223
04224
04225 ++nseq;
04226 k = 0;
04227 }
04228 }
04229
04230
04231
04232
04233
04234
04235 max = 0;
04236 maxpos = 0;
04237 for (i = 0; i < nseq; i++) {
04238 if (seq_length[i] > max) {
04239 max = seq_length[i];
04240 maxpos = i;
04241 }
04242 }
04243
04244
04245
04246
04247
04248
04249 nn = 0;
04250 for (i = 0; i < maxpos; i++)
04251 nn += seq_length[i];
04252
04253
04254
04255
04256
04257 n = max;
04258 for (i = 0; i < n; i++, nn++) {
04259 xpos[i] = xpos[nn];
04260 lambda[i] = lambda[nn];
04261 ilambda[i] = ilambda[nn];
04262 }
04263
04264
04265
04266
04267
04268
04269 for (i = 1; i < n; i++) {
04270 gap = ilambda[i] - ilambda[i-1];
04271 for (j = 1; j < gap; j++) {
04272
04273 if (j == 1) {
04274
04275
04276
04277
04278
04279 disp = (lambda[i] - lambda[i-1]) / (xpos[i] - xpos[i-1]);
04280 }
04281
04282
04283
04284
04285
04286
04287 hi_start = xpos[i-1] + (line[ilambda[i-1] + j] - lambda[i-1]) / disp;
04288
04289
04290
04291
04292
04293
04294
04295
04296
04297
04298
04299
04300
04301 found = 0;
04302 for (k = 0; k < npeaks; k++) {
04303 if (fabs(peak[k] - hi_start) < 2) {
04304 for (l = n; l > i; l--) {
04305 xpos[l] = xpos[l-1];
04306 lambda[l] = lambda[l-1];
04307 ilambda[l] = ilambda[l-1];
04308 }
04309 xpos[i] = peak[k];
04310 lambda[i] = line[ilambda[i-1] + j];
04311 ilambda[i] = ilambda[i-1] + j;
04312 ++n;
04313 found = 1;
04314 break;
04315 }
04316 }
04317 if (found)
04318 break;
04319 }
04320 }
04321
04322
04323
04324
04325
04326
04327 found = 1;
04328 while (ilambda[n-1] < nlines - 1 && found) {
04329
04330
04331
04332
04333
04334
04335 if (n > 1)
04336 disp = (lambda[n-1] - lambda[n-2]) / (xpos[n-1] - xpos[n-2]);
04337 else
04338 disp = 0.0;
04339
04340 if (disp > max_disp || disp < min_disp)
04341 break;
04342
04343
04344
04345
04346
04347
04348
04349 hi_start = xpos[n-1] + (line[ilambda[n-1] + 1] - lambda[n-1]) / disp;
04350
04351
04352
04353
04354
04355
04356
04357
04358
04359 found = 0;
04360 min = fabs(peak[0] - hi_start);
04361 minpos = 0;
04362 for (k = 1; k < npeaks; k++) {
04363 if (min > fabs(peak[k] - hi_start)) {
04364 min = fabs(peak[k] - hi_start);
04365 minpos = k;
04366 }
04367 }
04368 if (min < 6 && fabs(peak[minpos] - xpos[n-1]) > 1.0) {
04369 xpos[n] = peak[minpos];
04370 lambda[n] = line[ilambda[n-1] + 1];
04371 ilambda[n] = ilambda[n-1] + 1;
04372 ++n;
04373 found = 1;
04374 }
04375 }
04376
04377
04378
04379
04380
04381
04382 found = 1;
04383 while (ilambda[0] > 0 && found) {
04384
04385
04386
04387
04388
04389
04390 disp = (lambda[1] - lambda[0]) / (xpos[1] - xpos[0]);
04391
04392 if (disp > max_disp || disp < min_disp)
04393 break;
04394
04395
04396
04397
04398
04399
04400
04401 hi_start = xpos[0] - (lambda[0] - line[ilambda[0] - 1]) / disp;
04402
04403
04404
04405
04406
04407
04408
04409
04410
04411
04412 found = 0;
04413 min = fabs(peak[0] - hi_start);
04414 minpos = 0;
04415 for (k = 1; k < npeaks; k++) {
04416 if (min > fabs(peak[k] - hi_start)) {
04417 min = fabs(peak[k] - hi_start);
04418 minpos = k;
04419 }
04420 }
04421 if (min < 6 && fabs(peak[minpos] - xpos[0]) > 1.0) {
04422 for (j = n; j > 0; j--) {
04423 xpos[j] = xpos[j-1];
04424 lambda[j] = lambda[j-1];
04425 ilambda[j] = ilambda[j-1];
04426 }
04427 xpos[0] = peak[minpos];
04428 lambda[0] = line[ilambda[0] - 1];
04429 ilambda[0] = ilambda[0] - 1;
04430 ++n;
04431 found = 1;
04432 }
04433 }
04434 }
04435
04436
04437
04438
04439
04440
04441
04442
04443
04444
04445
04446
04447
04448
04449
04450
04451
04452
04453
04454
04455 for (i = 0; i < npeaks; i++)
04456 cpl_free(ident[i]);
04457 cpl_free(ident);
04458 cpl_free(nident);
04459 cpl_free(lident);
04460 cpl_free(ilambda);
04461 cpl_free(tmp_xpos);
04462 cpl_free(tmp_lambda);
04463 cpl_free(tmp_ilambda);
04464 cpl_free(peak_lo);
04465 cpl_free(flag);
04466 cpl_free(seq_length);
04467 cpl_free(peak_hi);
04468
04469 if (n == 0) {
04470 cpl_free(xpos);
04471 cpl_free(lambda);
04472 return NULL;
04473 }
04474
04475 return cpl_bivector_wrap_vectors(cpl_vector_wrap(n, xpos),
04476 cpl_vector_wrap(n, lambda));
04477 }
04478
04479
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
04536
04537 double mos_eval_dds(cpl_polynomial *ids, double blue, double red,
04538 double refwave, double pixel)
04539 {
04540 double yellow;
04541 double coeff;
04542 int zero = 0;
04543
04544 if (cpl_polynomial_eval_1d(ids, blue-refwave, NULL) > pixel)
04545 return 0.0;
04546
04547 if (cpl_polynomial_eval_1d(ids, red-refwave, NULL) < pixel)
04548 return 0.0;
04549
04550 yellow = (blue + red) / 2 - refwave;
04551
04552 coeff = cpl_polynomial_get_coeff(ids, &zero);
04553 cpl_polynomial_set_coeff(ids, &zero, coeff - pixel);
04554
04555 cpl_polynomial_solve_1d(ids, yellow, &yellow, 1);
04556
04557 cpl_polynomial_set_coeff(ids, &zero, coeff);
04558
04559 return yellow + refwave;
04560
04561 }
04562
04588 cpl_polynomial *mos_poly_wav2pix(cpl_bivector *pixwav, int order,
04589 double reject, int minlines,
04590 int *nlines, double *err)
04591 {
04592 const char *func = "mos_poly_wav2pix";
04593
04594 cpl_bivector *pixwav2;
04595 cpl_vector *wavel;
04596 cpl_vector *pixel;
04597 double *d_wavel;
04598 double *d_pixel;
04599 double pixpos;
04600 int fitlines;
04601 int rejection = 0;
04602 int i, j;
04603
04604 cpl_polynomial *ids;
04605
04606
04607 *nlines = 0;
04608 *err = 0;
04609
04610 if (pixwav == NULL) {
04611 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
04612 return NULL;
04613 }
04614
04615 fitlines = cpl_bivector_get_size(pixwav);
04616
04617 if (fitlines < minlines) {
04618 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
04619 return NULL;
04620 }
04621
04622
04623
04624
04625
04626
04627
04628 if (reject > 0.0)
04629 rejection = 1;
04630
04631 if (rejection)
04632 pixwav2 = cpl_bivector_duplicate(pixwav);
04633 else
04634 pixwav2 = pixwav;
04635
04636
04637
04638
04639
04640
04641
04642 pixel = cpl_bivector_get_x(pixwav2);
04643 wavel = cpl_bivector_get_y(pixwav2);
04644
04645
04646
04647
04648
04649
04650 if (rejection)
04651 cpl_bivector_unwrap_vectors(pixwav2);
04652
04653
04654
04655
04656
04657
04658 while (fitlines >= minlines) {
04659
04660 ids = cpl_polynomial_fit_1d_create(wavel, pixel, order, err);
04661 *err = sqrt(*err);
04662
04663 if (ids == NULL) {
04664 cpl_msg_debug(cpl_error_get_where(), cpl_error_get_message());
04665 cpl_msg_debug(func, "Fitting IDS");
04666 cpl_error_set_where(func);
04667 if (rejection) {
04668 cpl_vector_delete(wavel);
04669 cpl_vector_delete(pixel);
04670 }
04671 return NULL;
04672 }
04673
04674 if (rejection) {
04675
04676
04677
04678
04679
04680
04681 d_pixel = cpl_vector_unwrap(pixel);
04682 d_wavel = cpl_vector_unwrap(wavel);
04683
04684 for (i = 0, j = 0; i < fitlines; i++) {
04685 pixpos = cpl_polynomial_eval_1d(ids, d_wavel[i], NULL);
04686 if (fabs(pixpos - d_pixel[i]) < reject) {
04687 d_pixel[j] = d_pixel[i];
04688 d_wavel[j] = d_wavel[i];
04689 j++;
04690 }
04691 }
04692
04693 if (j == fitlines) {
04694 cpl_free(d_wavel);
04695 cpl_free(d_pixel);
04696 *nlines = fitlines;
04697 return ids;
04698 }
04699 else {
04700 fitlines = j;
04701 cpl_polynomial_delete(ids);
04702 if (fitlines >= minlines) {
04703 pixel = cpl_vector_wrap(fitlines, d_pixel);
04704 wavel = cpl_vector_wrap(fitlines, d_wavel);
04705 }
04706 else {
04707 cpl_free(d_wavel);
04708 cpl_free(d_pixel);
04709 cpl_error_set(func, CPL_ERROR_CONTINUE);
04710 return NULL;
04711 }
04712 }
04713 }
04714 else {
04715 *nlines = fitlines;
04716 return ids;
04717 }
04718 }
04719
04720 return ids;
04721 }
04722
04723
04748 cpl_polynomial *mos_poly_pix2wav(cpl_bivector *pixwav, int order,
04749 double reject, int minlines,
04750 int *nlines, double *err)
04751 {
04752
04753 cpl_bivector *wavpix;
04754 cpl_vector *wavel;
04755 cpl_vector *pixel;
04756
04757 cpl_polynomial *dds;
04758
04759
04760
04761
04762
04763
04764 pixel = cpl_bivector_get_x(pixwav);
04765 wavel = cpl_bivector_get_y(pixwav);
04766
04767 wavpix = cpl_bivector_wrap_vectors(wavel, pixel);
04768
04769 dds = mos_poly_wav2pix(wavpix, order, reject, minlines, nlines, err);
04770
04771 cpl_bivector_unwrap_vectors(wavpix);
04772
04773 return dds;
04774
04775 }
04776
04777
04800 cpl_bivector *mos_find_peaks(const float *spectrum, int length, cpl_vector *lines,
04801 cpl_polynomial *ids, double refwave, int sradius)
04802 {
04803 const char *func = "mos_find_peaks";
04804
04805 double *data;
04806 double *d_pixel;
04807 double *d_wavel;
04808 float pos;
04809 int nlines;
04810 int pixel;
04811 int i, j;
04812
04813
04814 if (spectrum == NULL || lines == NULL || ids == NULL) {
04815 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
04816 return NULL;
04817 }
04818
04819 nlines = cpl_vector_get_size(lines);
04820
04821 if (sradius < 1 || length < 2*sradius+1 || nlines < 1) {
04822 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
04823 return NULL;
04824 }
04825
04826 d_wavel = cpl_malloc(nlines * sizeof(double));
04827 d_pixel = cpl_malloc(nlines * sizeof(double));
04828
04829 data = cpl_vector_get_data(lines);
04830
04831 for (i = 0, j = 0; i < nlines; i++) {
04832 pixel = cpl_polynomial_eval_1d(ids, data[i]-refwave, NULL) + 0.5;
04833 if (pixel - sradius < 0 || pixel + sradius >= length)
04834 continue;
04835 if (0 == peakPosition(spectrum+pixel-sradius, 2*sradius+1, &pos, 1)) {
04836 pos += pixel - sradius;
04837 d_pixel[j] = pos;
04838 d_wavel[j] = data[i];
04839 j++;
04840 }
04841 }
04842
04843 if (j > 0) {
04844 return cpl_bivector_wrap_vectors(cpl_vector_wrap(j, d_pixel),
04845 cpl_vector_wrap(j, d_wavel));
04846 }
04847 else {
04848 cpl_free(d_wavel);
04849 cpl_free(d_pixel);
04850 cpl_error_set(func, CPL_ERROR_ILLEGAL_OUTPUT);
04851 return NULL;
04852 }
04853 }
04854
04855
04973 cpl_image *mos_wavelength_calibration_raw(const cpl_image *image,
04974 cpl_vector *lines,
04975 double dispersion, float level,
04976 int sradius, int order,
04977 double reject, double refwave,
04978 double *wavestart, double *waveend,
04979 int *nlines, double *error,
04980 cpl_table *idscoeff,
04981 cpl_image *calibration,
04982 cpl_image *residuals,
04983 cpl_table *restable,
04984 cpl_mask *refmask)
04985 {
04986
04987 const char *func = "mos_wavelength_calibration_raw";
04988
04989 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
04990
04991
04992 double tolerance = 20.0;
04993 int step = 10;
04994
04995 char name[MAX_COLNAME];
04996 cpl_image *resampled;
04997 cpl_bivector *output;
04998 cpl_bivector *new_output;
04999 cpl_vector *peaks;
05000 cpl_vector *wavel;
05001 cpl_polynomial *ids;
05002 cpl_polynomial *lin;
05003 cpl_matrix *kernel;
05004 double ids_err;
05005 double max_disp, min_disp;
05006 double *line;
05007 double firstLambda, lastLambda, lambda;
05008 double value, wave, pixe;
05009 cpl_binary *mdata;
05010 const float *sdata;
05011 float *rdata;
05012 float *idata;
05013 float *ddata;
05014 float v1, v2, vi;
05015 float fpixel;
05016 int *have_it;
05017 int pixstart, pixend;
05018 int extrapolation;
05019 int nref;
05020 int nl, nx, ny, pixel;
05021 int countLines, usedLines;
05022 int uorder;
05023 int in, first, last;
05024 int width, uradius;
05025 int i, j, k;
05026
05027
05028 if (dispersion == 0.0) {
05029 cpl_msg_error(func, "The expected dispersion (A/pixel) must be given");
05030 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05031 return NULL;
05032 }
05033
05034 if (dispersion < 0.0) {
05035 cpl_msg_error(func, "The expected dispersion must be positive");
05036 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05037 return NULL;
05038 }
05039
05040 max_disp = dispersion + dispersion * tolerance / 100;
05041 min_disp = dispersion - dispersion * tolerance / 100;
05042
05043 if (order < 1) {
05044 cpl_msg_error(func, "The order of the fitting polynomial "
05045 "must be at least 1");
05046 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05047 return NULL;
05048 }
05049
05050 if (image == NULL || lines == NULL) {
05051 cpl_msg_error(func, "Both spectral exposure and reference line "
05052 "catalog are required in input");
05053 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05054 return NULL;
05055 }
05056
05057 nx = cpl_image_get_size_x(image);
05058 ny = cpl_image_get_size_y(image);
05059 sdata = cpl_image_get_data_float_const(image);
05060
05061 nref = cpl_vector_get_size(lines);
05062 line = cpl_vector_get_data(lines);
05063
05064 if (*wavestart < 1.0 && *waveend < 1.0) {
05065 firstLambda = line[0];
05066 lastLambda = line[nref-1];
05067 extrapolation = (lastLambda - firstLambda) / 10;
05068 firstLambda -= extrapolation;
05069 lastLambda += extrapolation;
05070 *wavestart = firstLambda;
05071 *waveend = lastLambda;
05072 }
05073 else {
05074 firstLambda = *wavestart;
05075 lastLambda = *waveend;
05076 }
05077
05078 nl = (lastLambda - firstLambda) / dispersion;
05079 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
05080 rdata = cpl_image_get_data_float(resampled);
05081
05082 if (calibration)
05083 idata = cpl_image_get_data_float(calibration);
05084
05085 if (residuals)
05086 ddata = cpl_image_get_data_float(residuals);
05087
05088 if (idscoeff)
05089 for (j = 0; j <= order; j++)
05090 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
05091
05092 if (restable) {
05093 cpl_table_set_size(restable, nref);
05094 cpl_table_new_column(restable, "wavelength", CPL_TYPE_DOUBLE);
05095 cpl_table_copy_data_double(restable, "wavelength", line);
05096 for (i = 0; i < ny; i += step) {
05097 snprintf(name, MAX_COLNAME, "r%d", i);
05098 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05099 snprintf(name, MAX_COLNAME, "d%d", i);
05100 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05101 snprintf(name, MAX_COLNAME, "p%d", i);
05102 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05103 }
05104 }
05105
05106
05107
05108
05109
05110
05111
05112 for (i = 0; i < ny; i++) {
05113 width = mos_lines_width(sdata + i*nx, nx);
05114 if (sradius > 0) {
05115 if (width > sradius) {
05116 uradius = width;
05117 }
05118 else {
05119 uradius = sradius;
05120 }
05121 }
05122 if (width < 5)
05123 width = 5;
05124 peaks = mos_peak_candidates(sdata + i*nx, nx, level, width);
05125 if (peaks) {
05126 peaks = mos_refine_peaks(sdata + i*nx, nx, peaks, width);
05127 }
05128 if (peaks) {
05129 output = mos_identify_peaks(peaks, lines, min_disp, max_disp, 0.05);
05130 if (output) {
05131 countLines = cpl_bivector_get_size(output);
05132 if (countLines < 4) {
05133 cpl_bivector_delete(output);
05134 cpl_vector_delete(peaks);
05135 if (nlines)
05136 nlines[i] = 0;
05137 if (error)
05138 error[i] = 0.0;
05139 continue;
05140 }
05141
05142
05143
05144
05145
05146 wavel = cpl_bivector_get_y(output);
05147 cpl_vector_subtract_scalar(wavel, refwave);
05148
05149 uorder = countLines / 2 - 1;
05150 if (uorder > order)
05151 uorder = order;
05152
05153
05154
05155
05156
05157
05158
05159
05160
05161
05162 ids = mos_poly_wav2pix(output, uorder, reject,
05163 2 * (uorder + 1), &usedLines,
05164 &ids_err);
05165
05166 if (ids == NULL) {
05167 cpl_bivector_delete(output);
05168 cpl_vector_delete(peaks);
05169 if (nlines)
05170 nlines[i] = 0;
05171 if (error)
05172 error[i] = 0.0;
05173 cpl_error_reset();
05174 continue;
05175 }
05176
05177 if (idscoeff) {
05178
05179
05180
05181
05182
05183
05184
05185 for (k = 0; k <= order; k++) {
05186 if (k > uorder) {
05187 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
05188 }
05189 else {
05190 cpl_table_set_double(idscoeff, clab[k], i,
05191 cpl_polynomial_get_coeff(ids, &k));
05192 }
05193 }
05194 }
05195
05196 if (sradius > 0) {
05197
05198
05199
05200
05201
05202 new_output = mos_find_peaks(sdata + i*nx, nx, lines,
05203 ids, refwave, uradius);
05204
05205 if (new_output) {
05206 cpl_bivector_delete(output);
05207 output = new_output;
05208 }
05209 else
05210 cpl_error_reset();
05211
05212
05213 cpl_polynomial_delete(ids);
05214
05215 countLines = cpl_bivector_get_size(output);
05216
05217 if (countLines < 4) {
05218 cpl_bivector_delete(output);
05219 cpl_vector_delete(peaks);
05220
05221
05222
05223
05224
05225
05226
05227 if (nlines)
05228 nlines[i] = 0;
05229 if (error)
05230 error[i] = 0.0;
05231 if (idscoeff)
05232 for (k = 0; k <= order; k++)
05233 cpl_table_set_invalid(idscoeff, clab[k], i);
05234 continue;
05235 }
05236
05237 wavel = cpl_bivector_get_y(output);
05238 cpl_vector_subtract_scalar(wavel, refwave);
05239
05240 uorder = countLines / 2 - 1;
05241 if (uorder > order)
05242 uorder = order;
05243
05244 ids = mos_poly_wav2pix(output, uorder, reject,
05245 2 * (uorder + 1), &usedLines,
05246 &ids_err);
05247
05248 if (ids == NULL) {
05249 cpl_bivector_delete(output);
05250 cpl_vector_delete(peaks);
05251
05252
05253
05254
05255
05256
05257
05258 if (nlines)
05259 nlines[i] = 0;
05260 if (error)
05261 error[i] = 0.0;
05262 if (idscoeff)
05263 for (k = 0; k <= order; k++)
05264 cpl_table_set_invalid(idscoeff, clab[k], i);
05265 cpl_error_reset();
05266 continue;
05267 }
05268
05269 if (idscoeff) {
05270 for (k = 0; k <= order; k++) {
05271 if (k > uorder) {
05272 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
05273 }
05274 else {
05275 cpl_table_set_double(idscoeff, clab[k], i,
05276 cpl_polynomial_get_coeff(ids, &k));
05277 }
05278 }
05279 }
05280
05281 }
05282
05283 if (nlines)
05284 nlines[i] = usedLines;
05285 if (error)
05286 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
05287
05288 pixstart = cpl_polynomial_eval_1d(ids,
05289 cpl_bivector_get_y_data(output)[0], NULL);
05290 pixend = cpl_polynomial_eval_1d(ids,
05291 cpl_bivector_get_y_data(output)[countLines-1], NULL);
05292 extrapolation = (pixend - pixstart) / 5;
05293 pixstart -= extrapolation;
05294 pixend += extrapolation;
05295 if (pixstart < 0)
05296 pixstart = 0;
05297 if (pixend > nx)
05298 pixend = nx;
05299
05300
05301
05302
05303
05304 if (calibration) {
05305 for (j = pixstart; j < pixend; j++) {
05306 (idata + i*nx)[j] = mos_eval_dds(ids, firstLambda,
05307 lastLambda, refwave,
05308 j);
05309 }
05310 }
05311
05312
05313
05314
05315
05316 for (j = 0; j < nl; j++) {
05317 lambda = firstLambda + j * dispersion;
05318 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
05319 NULL);
05320 pixel = fpixel;
05321 if (pixel >= 0 && pixel < nx-1) {
05322 v1 = (sdata + i*nx)[pixel];
05323 v2 = (sdata + i*nx)[pixel+1];
05324 vi = v1 + (v2-v1)*(fpixel-pixel);
05325 (rdata + i*nl)[j] = vi;
05326 }
05327 }
05328
05329
05330
05331
05332
05333 if (residuals || (restable && !(i%step))) {
05334 if (restable && !(i%step)) {
05335 lin = cpl_polynomial_new(1);
05336 for (k = 0; k < 2; k++)
05337 cpl_polynomial_set_coeff(lin, &k,
05338 cpl_polynomial_get_coeff(ids, &k));
05339 }
05340 for (j = 0; j < countLines; j++) {
05341 pixe = cpl_bivector_get_x_data(output)[j];
05342 wave = cpl_bivector_get_y_data(output)[j];
05343 value = pixe - cpl_polynomial_eval_1d(ids, wave, NULL);
05344 if (residuals) {
05345 pixel = pixe + 0.5;
05346 (ddata + i*nx)[pixel] = value;
05347 }
05348 if (restable && !(i%step)) {
05349 for (k = 0; k < nref; k++) {
05350 if (fabs(line[k] - refwave - wave) < 0.1) {
05351 snprintf(name, MAX_COLNAME, "r%d", i);
05352 cpl_table_set_double(restable, name,
05353 k, value);
05354 value = pixe
05355 - cpl_polynomial_eval_1d(lin, wave,
05356 NULL);
05357 snprintf(name, MAX_COLNAME, "d%d", i);
05358 cpl_table_set_double(restable, name,
05359 k, value);
05360 snprintf(name, MAX_COLNAME, "p%d", i);
05361 cpl_table_set_double(restable, name,
05362 k, pixe);
05363 break;
05364 }
05365 }
05366 }
05367 }
05368 if (restable && !(i%step)) {
05369 cpl_polynomial_delete(lin);
05370 }
05371 }
05372
05373
05374
05375
05376
05377 if (refmask) {
05378 mdata = cpl_mask_get_data(refmask);
05379 pixel = cpl_polynomial_eval_1d(ids, 0.0, NULL) + 0.5;
05380 if (pixel - 1 >= 0 && pixel + 1 < nx) {
05381 mdata[pixel-1 + i*nx] = CPL_BINARY_1;
05382 mdata[pixel + i*nx] = CPL_BINARY_1;
05383 mdata[pixel+1 + i*nx] = CPL_BINARY_1;
05384 }
05385 }
05386
05387 cpl_polynomial_delete(ids);
05388 cpl_bivector_delete(output);
05389 }
05390 cpl_vector_delete(peaks);
05391 }
05392 }
05393
05394 if (refmask) {
05395 kernel = cpl_matrix_new(3, 3);
05396 cpl_matrix_set(kernel, 0, 1, 1.0);
05397 cpl_matrix_set(kernel, 1, 1, 1.0);
05398 cpl_matrix_set(kernel, 2, 1, 1.0);
05399
05400 cpl_mask_dilation(refmask, kernel);
05401 cpl_mask_erosion(refmask, kernel);
05402 cpl_mask_erosion(refmask, kernel);
05403 cpl_mask_dilation(refmask, kernel);
05404
05405 cpl_matrix_delete(kernel);
05406
05407
05408
05409
05410
05411 mdata = cpl_mask_get_data(refmask);
05412 have_it = cpl_calloc(ny, sizeof(int));
05413
05414 for (i = 0; i < ny; i++, mdata += nx) {
05415 for (j = 0; j < nx; j++) {
05416 if (mdata[j] == CPL_BINARY_1) {
05417 have_it[i] = j;
05418 break;
05419 }
05420 }
05421 }
05422
05423 mdata = cpl_mask_get_data(refmask);
05424 in = 0;
05425 first = last = 0;
05426
05427 for (i = 0; i < ny; i++) {
05428 if (have_it[i]) {
05429 if (!in) {
05430 in = 1;
05431 if (first) {
05432 last = i;
05433 if (abs(have_it[first] - have_it[last]) < 3) {
05434 for (j = first; j < last; j++) {
05435 mdata[have_it[first] + nx*j + 0] = CPL_BINARY_1;
05436 mdata[have_it[first] + nx*j + 1] = CPL_BINARY_1;
05437 mdata[have_it[first] + nx*j + 2] = CPL_BINARY_1;
05438 }
05439 }
05440 }
05441 }
05442 }
05443 else {
05444 if (in) {
05445 in = 0;
05446 first = i - 1;
05447 }
05448 }
05449 }
05450
05451 cpl_free(have_it);
05452
05453 }
05454
05455
05456
05457
05458
05459
05460
05461
05462
05463
05464
05465 return resampled;
05466 }
05467
05468
05490
05491
05492
05493
05494
05495
05496
05497
05498
05499
05500
05501
05502
05503
05504
05505
05506
05507
05508
05509
05510
05511
05512
05513
05514
05515
05516
05517
05518
05519
05520
05521
05522
05523
05524
05525
05526
05527
05528
05529
05530
05531
05532
05533
05534
05535
05536
05537
05538
05539
05540
05541
05542
05543
05544
05545
05546
05547
05548
05549
05550
05551
05552
05553
05554
05555
05577 cpl_table *mos_locate_spectra(cpl_mask *mask)
05578 {
05579 const char *func = "mos_locate_spectra";
05580
05581 cpl_apertures *slits;
05582 cpl_image *labimage;
05583 cpl_image *refimage;
05584 cpl_table *slitpos;
05585 cpl_propertylist *sort_col;
05586 int nslits;
05587 int i;
05588
05589
05590 if (mask == NULL) {
05591 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05592 return NULL;
05593 }
05594
05595 labimage = cpl_image_labelise_mask_create(mask, &nslits);
05596
05597 if (nslits < 1) {
05598 cpl_image_delete(labimage);
05599 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05600 return NULL;
05601 }
05602
05603 refimage = cpl_image_new_from_mask(mask);
05604
05605 slits = cpl_apertures_new_from_image(refimage, labimage);
05606
05607 cpl_image_delete(labimage);
05608 cpl_image_delete(refimage);
05609
05610 nslits = cpl_apertures_get_size(slits);
05611 if (nslits < 1) {
05612 cpl_apertures_delete(slits);
05613 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05614 return NULL;
05615 }
05616
05617 slitpos = cpl_table_new(nslits);
05618 cpl_table_new_column(slitpos, "xtop", CPL_TYPE_DOUBLE);
05619 cpl_table_new_column(slitpos, "ytop", CPL_TYPE_DOUBLE);
05620 cpl_table_new_column(slitpos, "xbottom", CPL_TYPE_DOUBLE);
05621 cpl_table_new_column(slitpos, "ybottom", CPL_TYPE_DOUBLE);
05622 cpl_table_set_column_unit(slitpos, "xtop", "pixel");
05623 cpl_table_set_column_unit(slitpos, "ytop", "pixel");
05624 cpl_table_set_column_unit(slitpos, "xbottom", "pixel");
05625 cpl_table_set_column_unit(slitpos, "ybottom", "pixel");
05626
05627 for (i = 0; i < nslits; i++) {
05628 cpl_table_set_double(slitpos, "xtop", i,
05629 cpl_apertures_get_top_x(slits, i+1) - 1);
05630 cpl_table_set_double(slitpos, "ytop", i,
05631 cpl_apertures_get_top(slits, i+1));
05632 cpl_table_set_double(slitpos, "xbottom", i,
05633 cpl_apertures_get_bottom_x(slits, i+1) - 1);
05634 cpl_table_set_double(slitpos, "ybottom", i,
05635 cpl_apertures_get_bottom(slits, i+1));
05636 }
05637
05638 cpl_apertures_delete(slits);
05639
05640 sort_col = cpl_propertylist_new();
05641 cpl_propertylist_append_bool(sort_col, "ytop", 1);
05642 cpl_table_sort(slitpos, sort_col);
05643 cpl_propertylist_delete(sort_col);
05644
05645 return slitpos;
05646
05647 }
05648
05649
05665 cpl_error_code mos_validate_slits(cpl_table *slits)
05666 {
05667 const char *func = "mos_validate_slits";
05668
05669
05670 if (slits == NULL)
05671 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05672
05673 if (1 != cpl_table_has_column(slits, "xtop"))
05674 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05675
05676 if (1 != cpl_table_has_column(slits, "ytop"))
05677 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05678
05679 if (1 != cpl_table_has_column(slits, "xbottom"))
05680 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05681
05682 if (1 != cpl_table_has_column(slits, "ybottom"))
05683 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05684
05685 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "xtop"))
05686 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05687
05688 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "ytop"))
05689 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05690
05691 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "xbottom"))
05692 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05693
05694 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "ybottom"))
05695 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05696
05697 return CPL_ERROR_NONE;
05698 }
05699
05700
05729 cpl_error_code mos_rotate_slits(cpl_table *slits, int rotation, int nx, int ny)
05730 {
05731 const char *func = "mos_rotate_slits";
05732
05733 cpl_error_code error;
05734 char aux_name[] = "_0";
05735 int i;
05736
05737
05738 rotation %= 4;
05739 if (rotation < 0)
05740 rotation += 4;
05741
05742 if (rotation == 0)
05743 return CPL_ERROR_NONE;
05744
05745 error = mos_validate_slits(slits);
05746 if (error)
05747 return cpl_error_set(func, error);
05748
05749 if (rotation == 1 || rotation == 3) {
05750
05751
05752
05753
05754
05755 for (i = 0; i < 77; i++)
05756 if (1 == cpl_table_has_column(slits, aux_name))
05757 aux_name[1]++;
05758 if (1 == cpl_table_has_column(slits, aux_name))
05759 return cpl_error_set(func, CPL_ERROR_CONTINUE);
05760 cpl_table_name_column(slits, "xtop", aux_name);
05761 cpl_table_name_column(slits, "ytop", "xtop");
05762 cpl_table_name_column(slits, aux_name, "ytop");
05763 cpl_table_name_column(slits, "xbottom", aux_name);
05764 cpl_table_name_column(slits, "ybottom", "xbottom");
05765 cpl_table_name_column(slits, aux_name, "ybottom");
05766 }
05767
05768 if (rotation == 1 || rotation == 2) {
05769 cpl_table_multiply_scalar(slits, "xtop", -1.0);
05770 cpl_table_multiply_scalar(slits, "xbottom", -1.0);
05771 cpl_table_add_scalar(slits, "xtop", nx);
05772 cpl_table_add_scalar(slits, "xbottom", nx);
05773 }
05774
05775 if (rotation == 3 || rotation == 2) {
05776 cpl_table_multiply_scalar(slits, "ytop", -1.0);
05777 cpl_table_multiply_scalar(slits, "ybottom", -1.0);
05778 cpl_table_add_scalar(slits, "ytop", ny);
05779 cpl_table_add_scalar(slits, "ybottom", ny);
05780 }
05781
05782 return CPL_ERROR_NONE;
05783 }
05784
05785
05843 cpl_table *mos_identify_slits(cpl_table *slits, cpl_table *maskslits,
05844 cpl_table *global)
05845 {
05846 cpl_array *top_ident;
05847 cpl_array *bot_ident;
05848 cpl_matrix *mdata;
05849 cpl_matrix *mpattern;
05850 cpl_matrix *top_data;
05851 cpl_matrix *top_pattern;
05852 cpl_matrix *top_mdata;
05853 cpl_matrix *top_mpattern;
05854 cpl_matrix *bot_data;
05855 cpl_matrix *bot_pattern;
05856 cpl_matrix *bot_mdata;
05857 cpl_matrix *bot_mpattern;
05858 cpl_propertylist *sort_col;
05859 double *xtop;
05860 double *ytop;
05861 double *xmtop;
05862 double *ymtop;
05863 double *xbot;
05864 double *ybot;
05865 double *xmbot;
05866 double *ymbot;
05867 double top_scale, bot_scale;
05868 double angle, top_angle, bot_angle;
05869 double xmse, ymse;
05870 double xrms, top_xrms, bot_xrms;
05871 double yrms, top_yrms, bot_yrms;
05872 int nslits;
05873 int nmaskslits, use_pattern;
05874 int found_slits, found_slits_top, found_slits_bot;
05875 int degree;
05876 int i;
05877 cpl_table *positions;
05878 cpl_error_code error;
05879
05880 cpl_vector *point;
05881 double *dpoint;
05882 cpl_vector *xpos;
05883 cpl_vector *ypos;
05884 cpl_vector *xmpos;
05885 cpl_vector *ympos;
05886 cpl_bivector *mpos;
05887 cpl_polynomial *xpoly = NULL;
05888 cpl_polynomial *ypoly = NULL;
05889 cpl_polynomial *top_xpoly = NULL;
05890 cpl_polynomial *top_ypoly = NULL;
05891 cpl_polynomial *bot_xpoly = NULL;
05892 cpl_polynomial *bot_ypoly = NULL;
05893
05894
05895 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 3, 0)
05896 positions = mos_identify_slits_fast(slits, maskslits, global);
05897 if (positions == NULL)
05898 cpl_error_set_where(cpl_func);
05899 return positions;
05900 #endif
05901
05902 error = mos_validate_slits(slits);
05903 if (error) {
05904 cpl_msg_error(cpl_func, "CCD slits table validation: %s",
05905 cpl_error_get_message());
05906 cpl_error_set(cpl_func, error);
05907 return NULL;
05908 }
05909
05910 error = mos_validate_slits(maskslits);
05911 if (error) {
05912 cpl_msg_error(cpl_func, "Mask slits table validation: %s",
05913 cpl_error_get_message());
05914 cpl_error_set(cpl_func, error);
05915 return NULL;
05916 }
05917
05918 if (1 != cpl_table_has_column(maskslits, "slit_id")) {
05919 cpl_msg_error(cpl_func, "Missing slits identifiers");
05920 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
05921 return NULL;
05922 }
05923
05924 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits, "slit_id")) {
05925 cpl_msg_error(cpl_func, "Wrong type used for slits identifiers");
05926 cpl_error_set(cpl_func, CPL_ERROR_INVALID_TYPE);
05927 return NULL;
05928 }
05929
05930 nslits = cpl_table_get_nrow(slits);
05931 nmaskslits = cpl_table_get_nrow(maskslits);
05932
05933 if (nslits == 0 || nmaskslits == 0) {
05934 cpl_msg_error(cpl_func, "Empty slits table");
05935 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
05936 return NULL;
05937 }
05938
05939 if (nslits > 25) {
05940 cpl_msg_info(cpl_func, "Many slits: using 'fast' pattern matching...");
05941 positions = mos_identify_slits_fast(slits, maskslits, global);
05942 if (positions == NULL)
05943 cpl_error_set_where(cpl_func);
05944 return positions;
05945 }
05946
05947
05948
05949
05950
05951 sort_col = cpl_propertylist_new();
05952 cpl_propertylist_append_bool(sort_col, "ytop", 1);
05953 cpl_table_sort(slits, sort_col);
05954 cpl_table_sort(maskslits, sort_col);
05955 cpl_propertylist_delete(sort_col);
05956
05957
05958
05959
05960
05961 if (nslits < 3 && nmaskslits > nslits) {
05962
05963
05964
05965
05966
05967
05968
05969
05970 if (nslits > 1)
05971 cpl_msg_warning(cpl_func, "Cannot match the %d found CCD slits "
05972 "with the %d mask slits: process will continue "
05973 "using the detected CCD slits positions", nslits,
05974 nmaskslits);
05975 else
05976 cpl_msg_warning(cpl_func, "Cannot match the found CCD slit with "
05977 "the %d mask slits: process will continue using "
05978 "the detected CCD slit position", nmaskslits);
05979 return NULL;
05980 }
05981
05982 if (nmaskslits < 3 && nslits > nmaskslits) {
05983
05984
05985
05986
05987
05988
05989
05990 cpl_msg_warning(cpl_func, "Cannot match the %d found CCD slits with "
05991 "the %d mask slits: process will continue using "
05992 "the detected CCD slits positions", nslits,
05993 nmaskslits);
05994 return NULL;
05995 }
05996
05997
05998
05999
06000
06001
06002
06003
06004 xtop = cpl_table_get_data_double(slits, "xtop");
06005 ytop = cpl_table_get_data_double(slits, "ytop");
06006 xmtop = cpl_table_get_data_double(maskslits, "xtop");
06007 ymtop = cpl_table_get_data_double(maskslits, "ytop");
06008
06009 xbot = cpl_table_get_data_double(slits, "xbottom");
06010 ybot = cpl_table_get_data_double(slits, "ybottom");
06011 xmbot = cpl_table_get_data_double(maskslits, "xbottom");
06012 ymbot = cpl_table_get_data_double(maskslits, "ybottom");
06013
06014 top_data = cpl_matrix_new(2, nslits);
06015 top_pattern = cpl_matrix_new(2, nmaskslits);
06016 bot_data = cpl_matrix_new(2, nslits);
06017 bot_pattern = cpl_matrix_new(2, nmaskslits);
06018
06019 for (i = 0; i < nslits; i++)
06020 cpl_matrix_set(top_data, 0, i, xtop[i]);
06021
06022 for (i = 0; i < nslits; i++)
06023 cpl_matrix_set(top_data, 1, i, ytop[i]);
06024
06025 for (i = 0; i < nmaskslits; i++)
06026 cpl_matrix_set(top_pattern, 0, i, xmtop[i]);
06027
06028 for (i = 0; i < nmaskslits; i++)
06029 cpl_matrix_set(top_pattern, 1, i, ymtop[i]);
06030
06031 for (i = 0; i < nslits; i++)
06032 cpl_matrix_set(bot_data, 0, i, xbot[i]);
06033
06034 for (i = 0; i < nslits; i++)
06035 cpl_matrix_set(bot_data, 1, i, ybot[i]);
06036
06037 for (i = 0; i < nmaskslits; i++)
06038 cpl_matrix_set(bot_pattern, 0, i, xmbot[i]);
06039
06040 for (i = 0; i < nmaskslits; i++)
06041 cpl_matrix_set(bot_pattern, 1, i, ymbot[i]);
06042
06043 if (nmaskslits > nslits)
06044 use_pattern = nslits;
06045 else
06046 use_pattern = nmaskslits;
06047
06048 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 3, 0)
06049 top_ident = cpl_ppm_match_points(top_data, nslits, 1.0, top_pattern,
06050 use_pattern, 0.0, 0.1, 5, &top_mdata,
06051 &top_mpattern, &top_scale, &top_angle);
06052
06053 bot_ident = cpl_ppm_match_points(bot_data, nslits, 1.0, bot_pattern,
06054 use_pattern, 0.0, 0.1, 5, &bot_mdata,
06055 &bot_mpattern, &bot_scale, &bot_angle);
06056 #else
06057 top_ident = NULL;
06058 bot_ident = NULL;
06059 #endif
06060
06061 if (top_ident == NULL && bot_ident == NULL) {
06062 cpl_msg_warning(cpl_func, "Pattern matching failure: cannot match "
06063 "the %d found CCD slits with the %d mask slits: "
06064 "process will continue using the detected CCD "
06065 "slits positions", nslits, nmaskslits);
06066 return NULL;
06067 }
06068
06069 found_slits_top = 0;
06070 found_slits_bot = 0;
06071 if (top_ident && bot_ident) {
06072 cpl_msg_info(cpl_func, "Median platescale: %f +/- %f pixel/mm",
06073 (top_scale + bot_scale) / 2, fabs(top_scale - bot_scale));
06074 cpl_msg_info(cpl_func, "Median rotation: %f +/- %f degrees",
06075 (top_angle + bot_angle) / 2, fabs(top_angle - bot_angle));
06076 if (fabs(top_angle) < fabs(bot_angle))
06077 angle = fabs(top_angle);
06078 else
06079 angle = fabs(bot_angle);
06080 found_slits_top = cpl_matrix_get_ncol(top_mdata);
06081 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
06082 }
06083 else if (top_ident) {
06084 cpl_msg_info(cpl_func, "Median platescale: %f pixel/mm", top_scale);
06085 cpl_msg_info(cpl_func, "Median rotation: %f degrees", top_angle);
06086 angle = fabs(top_angle);
06087 found_slits_top = cpl_matrix_get_ncol(top_mdata);
06088 }
06089 else {
06090 cpl_msg_info(cpl_func, "Median platescale: %f pixel/mm", bot_scale);
06091 cpl_msg_info(cpl_func, "Median rotation: %f degrees", bot_angle);
06092 angle = fabs(bot_angle);
06093 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
06094 }
06095
06096 cpl_array_delete(top_ident);
06097 cpl_array_delete(bot_ident);
06098
06099 if (angle > 4.0) {
06100 cpl_msg_warning(cpl_func, "Uncertain pattern matching: the rotation "
06101 "angle is expected to be around zero. This match is "
06102 "rejected: the process will continue using the %d "
06103 "detected CCD slits positions", nslits);
06104 return NULL;
06105 }
06106
06107 found_slits = found_slits_top;
06108 if (found_slits < found_slits_bot)
06109 found_slits = found_slits_bot;
06110
06111 if (found_slits < 4) {
06112 cpl_msg_warning(cpl_func,
06113 "Too few safely identified slits: %d out of %d "
06114 "candidates (%d expected). Process will continue "
06115 "using the detected CCD slits positions", found_slits,
06116 nslits, nmaskslits);
06117 return NULL;
06118 }
06119
06120 cpl_msg_info(cpl_func, "Preliminary identified slits: %d out of %d "
06121 "candidates\n(%d expected)", found_slits, nslits,
06122 nmaskslits);
06123
06124 if (found_slits_top < 4)
06125 found_slits_top = 0;
06126
06127 if (found_slits_bot < 4)
06128 found_slits_bot = 0;
06129
06130
06131
06132
06133
06134
06135
06136 for (i = 0; i < 2; i++) {
06137 if (i) {
06138 found_slits = found_slits_top;
06139 mdata = top_mdata;
06140 mpattern = top_mpattern;
06141 }
06142 else {
06143 found_slits = found_slits_bot;
06144 mdata = bot_mdata;
06145 mpattern = bot_mpattern;
06146 }
06147
06148 if (found_slits == 0)
06149 continue;
06150 else if (found_slits < 10)
06151 degree = 1;
06152 else
06153 degree = 2;
06154
06155 xpos = cpl_vector_wrap(found_slits,
06156 cpl_matrix_get_data(mdata) );
06157 ypos = cpl_vector_wrap(found_slits,
06158 cpl_matrix_get_data(mdata) + found_slits);
06159 xmpos = cpl_vector_wrap(found_slits,
06160 cpl_matrix_get_data(mpattern) );
06161 ympos = cpl_vector_wrap(found_slits,
06162 cpl_matrix_get_data(mpattern) + found_slits);
06163 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
06164 xpoly = cpl_polynomial_fit_2d_create(mpos, xpos, degree, &xmse);
06165 ypoly = cpl_polynomial_fit_2d_create(mpos, ypos, degree, &ymse);
06166
06167 cpl_bivector_unwrap_vectors(mpos);
06168 cpl_vector_unwrap(xpos);
06169 cpl_vector_unwrap(ypos);
06170 cpl_vector_unwrap(xmpos);
06171 cpl_vector_unwrap(ympos);
06172 cpl_matrix_delete(mdata);
06173 cpl_matrix_delete(mpattern);
06174
06175 if (i) {
06176 top_xpoly = xpoly;
06177 top_ypoly = ypoly;
06178 top_xrms = sqrt(xmse*2*degree/(found_slits - 1));
06179 top_yrms = sqrt(ymse*2*degree/(found_slits - 1));
06180 }
06181 else {
06182 bot_xpoly = xpoly;
06183 bot_ypoly = ypoly;
06184 bot_xrms = sqrt(xmse*2*degree/(found_slits - 1));
06185 bot_yrms = sqrt(ymse*2*degree/(found_slits - 1));
06186 }
06187 }
06188
06189 if (top_xpoly && bot_xpoly) {
06190 if (top_xrms < bot_xrms) {
06191 xrms = top_xrms;
06192 xpoly = top_xpoly;
06193 cpl_polynomial_delete(bot_xpoly);
06194 }
06195 else {
06196 xrms = bot_xrms;
06197 xpoly = bot_xpoly;
06198 cpl_polynomial_delete(top_xpoly);
06199 }
06200 }
06201 else if (top_xpoly) {
06202 xrms = top_xrms;
06203 xpoly = top_xpoly;
06204 }
06205 else {
06206 xrms = bot_xrms;
06207 xpoly = bot_xpoly;
06208 }
06209
06210 if (top_ypoly && bot_ypoly) {
06211 if (top_yrms < bot_yrms) {
06212 yrms = top_yrms;
06213 ypoly = top_ypoly;
06214 cpl_polynomial_delete(bot_ypoly);
06215 }
06216 else {
06217 yrms = bot_yrms;
06218 ypoly = bot_ypoly;
06219 cpl_polynomial_delete(top_ypoly);
06220 }
06221 }
06222 else if (top_ypoly) {
06223 yrms = top_yrms;
06224 ypoly = top_ypoly;
06225 }
06226 else {
06227 yrms = bot_yrms;
06228 ypoly = bot_ypoly;
06229 }
06230
06231 if (xpoly == NULL || ypoly == NULL) {
06232 cpl_msg_warning(cpl_func, "Fit failure: the accuracy of the "
06233 "identified slits positions cannot be improved.");
06234 cpl_polynomial_delete(xpoly);
06235 cpl_polynomial_delete(ypoly);
06236 cpl_error_reset();
06237 return NULL;
06238 }
06239
06240 cpl_msg_info(cpl_func,
06241 "Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
06242 xrms, yrms);
06243
06244 if (global) {
06245 write_global_distortion(global, 0, xpoly);
06246 write_global_distortion(global, 7, ypoly);
06247 }
06248
06249
06250
06251
06252
06253
06254 positions = cpl_table_duplicate(maskslits);
06255 cpl_table_duplicate_column(positions, "xmtop", positions, "xtop");
06256 cpl_table_duplicate_column(positions, "ymtop", positions, "ytop");
06257 cpl_table_duplicate_column(positions, "xmbottom", positions, "xbottom");
06258 cpl_table_duplicate_column(positions, "ymbottom", positions, "ybottom");
06259
06260 point = cpl_vector_new(2);
06261 dpoint = cpl_vector_get_data(point);
06262
06263 for (i = 0; i < nmaskslits; i++) {
06264 dpoint[0] = cpl_table_get_double(positions, "xmtop", i, NULL);
06265 dpoint[1] = cpl_table_get_double(positions, "ymtop", i, NULL);
06266 cpl_table_set_double(positions, "xtop", i,
06267 cpl_polynomial_eval(xpoly, point));
06268 cpl_table_set_double(positions, "ytop", i,
06269 cpl_polynomial_eval(ypoly, point));
06270 dpoint[0] = cpl_table_get_double(positions, "xmbottom", i, NULL);
06271 dpoint[1] = cpl_table_get_double(positions, "ymbottom", i, NULL);
06272 cpl_table_set_double(positions, "xbottom", i,
06273 cpl_polynomial_eval(xpoly, point));
06274 cpl_table_set_double(positions, "ybottom", i,
06275 cpl_polynomial_eval(ypoly, point));
06276 }
06277
06278 cpl_vector_delete(point);
06279 cpl_polynomial_delete(xpoly);
06280 cpl_polynomial_delete(ypoly);
06281
06282 cpl_table_erase_column(positions, "xmtop");
06283 cpl_table_erase_column(positions, "ymtop");
06284 cpl_table_erase_column(positions, "xmbottom");
06285 cpl_table_erase_column(positions, "ymbottom");
06286
06287 if (nmaskslits > nslits)
06288 cpl_msg_info(cpl_func,
06289 "Finally identified slits: %d out of %d expected\n"
06290 "(%d recovered)", nmaskslits, nmaskslits,
06291 nmaskslits - nslits);
06292 else if (nmaskslits < nslits)
06293 cpl_msg_info(cpl_func,
06294 "Finally identified slits: %d out of %d expected\n"
06295 "(%d rejected)", nmaskslits, nmaskslits,
06296 nslits - nmaskslits);
06297 else
06298 cpl_msg_info(cpl_func,
06299 "Finally identified slits: %d out of %d expected",
06300 nmaskslits, nmaskslits);
06301
06302 return positions;
06303
06304 }
06305
06306
06307 cpl_table *mos_identify_slits_fast(cpl_table *slits, cpl_table *maskslits,
06308 cpl_table *global)
06309 {
06310 const char *func = "mos_identify_slits_fast";
06311
06312 cpl_propertylist *sort_col;
06313 cpl_table *positions;
06314 cpl_vector *scales;
06315 cpl_vector *angles;
06316 cpl_vector *point;
06317 cpl_vector *xpos;
06318 cpl_vector *ypos;
06319 cpl_vector *xmpos;
06320 cpl_vector *ympos;
06321 cpl_bivector *mpos;
06322 cpl_polynomial *xpoly = NULL;
06323 cpl_polynomial *ypoly = NULL;
06324 cpl_error_code error;
06325 int nslits;
06326 int nmaskslits;
06327 int found_slits;
06328 int i, j, k;
06329
06330 double dist1, dist2, dist3, dist, mindist;
06331 double scale, minscale, maxscale;
06332 double angle, minangle, maxangle;
06333 double *dscale;
06334 double *dangle;
06335 double *dpoint;
06336 double *xtop;
06337 double *ytop;
06338 double *xbottom;
06339 double *ybottom;
06340 double *xcenter;
06341 double *ycenter;
06342 double *xpseudo;
06343 double *ypseudo;
06344 int *slit_id;
06345 double *xmtop;
06346 double *ymtop;
06347 double *xmbottom;
06348 double *ymbottom;
06349 double *xmcenter;
06350 double *ymcenter;
06351 double *xmpseudo;
06352 double *ympseudo;
06353 double xmse, ymse;
06354 int *mslit_id;
06355 int *good;
06356 int minpos;
06357 int degree;
06358
06359 double sradius = 0.01;
06360 int in_sradius;
06361
06362 double pi = 3.14159265358979323846;
06363
06364
06365 error = mos_validate_slits(slits);
06366 if (error) {
06367 cpl_msg_error(func, "CCD slits table validation: %s",
06368 cpl_error_get_message());
06369 cpl_error_set(func, error);
06370 return NULL;
06371 }
06372
06373 error = mos_validate_slits(maskslits);
06374 if (error) {
06375 cpl_msg_error(func, "Mask slits table validation: %s",
06376 cpl_error_get_message());
06377 cpl_error_set(func, error);
06378 return NULL;
06379 }
06380
06381 if (1 != cpl_table_has_column(maskslits, "slit_id")) {
06382 cpl_msg_error(func, "Missing slits identifiers");
06383 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
06384 return NULL;
06385 }
06386
06387 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits, "slit_id")) {
06388 cpl_msg_error(func, "Wrong type used for slits identifiers");
06389 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
06390 return NULL;
06391 }
06392
06393 nslits = cpl_table_get_nrow(slits);
06394 nmaskslits = cpl_table_get_nrow(maskslits);
06395
06396 if (nslits == 0 || nmaskslits == 0) {
06397 cpl_msg_error(func, "Empty slits table");
06398 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
06399 return NULL;
06400 }
06401
06402
06403
06404
06405
06406
06407
06408 if (cpl_table_has_column(slits, "xcenter"))
06409 cpl_table_erase_column(slits, "xcenter");
06410
06411 if (cpl_table_has_column(slits, "ycenter"))
06412 cpl_table_erase_column(slits, "ycenter");
06413
06414 if (cpl_table_has_column(maskslits, "xcenter"))
06415 cpl_table_erase_column(maskslits, "xcenter");
06416
06417 if (cpl_table_has_column(maskslits, "ycenter"))
06418 cpl_table_erase_column(maskslits, "ycenter");
06419
06420 cpl_table_duplicate_column(slits, "xcenter", slits, "xtop");
06421 cpl_table_add_columns(slits, "xcenter", "xbottom");
06422 cpl_table_divide_scalar(slits, "xcenter", 2.0);
06423 cpl_table_duplicate_column(slits, "ycenter", slits, "ytop");
06424 cpl_table_add_columns(slits, "ycenter", "ybottom");
06425 cpl_table_divide_scalar(slits, "ycenter", 2.0);
06426
06427 cpl_table_duplicate_column(maskslits, "xcenter", maskslits, "xtop");
06428 cpl_table_add_columns(maskslits, "xcenter", "xbottom");
06429 cpl_table_divide_scalar(maskslits, "xcenter", 2.0);
06430 cpl_table_duplicate_column(maskslits, "ycenter", maskslits, "ytop");
06431 cpl_table_add_columns(maskslits, "ycenter", "ybottom");
06432 cpl_table_divide_scalar(maskslits, "ycenter", 2.0);
06433
06434
06435
06436
06437
06438
06439 sort_col = cpl_propertylist_new();
06440 cpl_propertylist_append_bool(sort_col, "ycenter", 1);
06441 cpl_table_sort(slits, sort_col);
06442 cpl_table_sort(maskslits, sort_col);
06443 cpl_propertylist_delete(sort_col);
06444
06445
06446
06447
06448
06449
06450 if (nslits < 3 && nmaskslits > nslits) {
06451
06452
06453
06454
06455
06456
06457
06458
06459 if (nslits > 1)
06460 cpl_msg_warning(func, "Cannot match the found CCD slit with the "
06461 "%d mask slits: process will continue using the "
06462 "detected CCD slit position", nmaskslits);
06463 else
06464 cpl_msg_warning(func, "Cannot match the %d found CCD slits with "
06465 "the %d mask slits: process will continue using "
06466 "the detected CCD slits positions", nslits,
06467 nmaskslits);
06468 return NULL;
06469 }
06470
06471 if (nslits <= 3 && nslits == nmaskslits) {
06472
06473 cpl_msg_warning(func, "Too few slits (%d) on mask and CCD", nslits);
06474 cpl_msg_warning(func, "Their detected positions are left unchanged");
06475
06476
06477
06478
06479
06480
06481
06482
06483
06484
06485 positions = cpl_table_duplicate(slits);
06486 cpl_table_erase_column(slits, "xcenter");
06487 cpl_table_erase_column(slits, "ycenter");
06488 cpl_table_duplicate_column(positions, "xmtop", maskslits, "xtop");
06489 cpl_table_duplicate_column(positions, "ymtop", maskslits, "ytop");
06490 cpl_table_duplicate_column(positions, "xmbottom", maskslits, "xbottom");
06491 cpl_table_duplicate_column(positions, "ymbottom", maskslits, "ybottom");
06492 cpl_table_duplicate_column(positions, "xmcenter", maskslits, "xcenter");
06493 cpl_table_duplicate_column(positions, "ymcenter", maskslits, "ycenter");
06494 cpl_table_duplicate_column(positions, "slit_id", maskslits, "slit_id");
06495 cpl_table_erase_column(maskslits, "xcenter");
06496 cpl_table_erase_column(maskslits, "ycenter");
06497
06498 if (nslits > 1) {
06499 xcenter = cpl_table_get_data_double(positions, "xcenter");
06500 ycenter = cpl_table_get_data_double(positions, "ycenter");
06501 xmcenter = cpl_table_get_data_double(positions, "xmcenter");
06502 ymcenter = cpl_table_get_data_double(positions, "ymcenter");
06503
06504 dist1 = (xcenter[0] - xcenter[1])*(xcenter[0] - xcenter[1])
06505 + (ycenter[0] - ycenter[1])*(ycenter[0] - ycenter[1]);
06506 dist2 = (xmcenter[0] - xmcenter[1])*(xmcenter[0] - xmcenter[1])
06507 + (ymcenter[0] - ymcenter[1])*(ymcenter[0] - ymcenter[1]);
06508 scale = sqrt(dist1/dist2);
06509
06510 if (nslits == 3) {
06511 dist1 = (xcenter[1] - xcenter[2])*(xcenter[1] - xcenter[2])
06512 + (ycenter[1] - ycenter[2])*(ycenter[1] - ycenter[2]);
06513 dist2 = (xmcenter[1] - xmcenter[2])*(xmcenter[1] - xmcenter[2])
06514 + (ymcenter[1] - ymcenter[2])*(ymcenter[1] - ymcenter[2]);
06515 scale += sqrt(dist1/dist2);
06516 scale /= 2;
06517 }
06518
06519 cpl_msg_info(func, "Platescale: %f pixel/mm", scale);
06520 }
06521
06522 return positions;
06523 }
06524
06525 if (nmaskslits < 3 && nslits > nmaskslits) {
06526
06527
06528
06529
06530
06531
06532
06533 cpl_msg_warning(func, "Cannot match the %d found CCD slits with "
06534 "the %d mask slits: process will continue using "
06535 "the detected CCD slits positions", nslits,
06536 nmaskslits);
06537 return NULL;
06538 }
06539
06540
06541
06542
06543
06544
06545
06546
06547
06548
06549
06550
06551
06552
06553
06554
06555
06556
06557
06558
06559
06560
06561
06562
06563
06564
06565
06566
06567 if (cpl_table_has_column(slits, "xpseudo"))
06568 cpl_table_erase_column(slits, "xpseudo");
06569
06570 if (cpl_table_has_column(slits, "ypseudo"))
06571 cpl_table_erase_column(slits, "ypseudo");
06572
06573 if (cpl_table_has_column(maskslits, "xpseudo"))
06574 cpl_table_erase_column(maskslits, "xpseudo");
06575
06576 if (cpl_table_has_column(maskslits, "ypseudo"))
06577 cpl_table_erase_column(maskslits, "ypseudo");
06578
06579 cpl_table_duplicate_column(slits, "xpseudo", slits, "xcenter");
06580 cpl_table_duplicate_column(slits, "ypseudo", slits, "ycenter");
06581
06582 xcenter = cpl_table_get_data_double(slits, "xcenter");
06583 ycenter = cpl_table_get_data_double(slits, "ycenter");
06584 xpseudo = cpl_table_get_data_double(slits, "xpseudo");
06585 ypseudo = cpl_table_get_data_double(slits, "ypseudo");
06586
06587 for (i = 1; i < nslits - 1; i++) {
06588 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
06589 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
06590 dist2 = (xcenter[i-1] - xcenter[i+1]) * (xcenter[i-1] - xcenter[i+1])
06591 + (ycenter[i-1] - ycenter[i+1]) * (ycenter[i-1] - ycenter[i+1]);
06592 dist3 = (xcenter[i] - xcenter[i+1]) * (xcenter[i] - xcenter[i+1])
06593 + (ycenter[i] - ycenter[i+1]) * (ycenter[i] - ycenter[i+1]);
06594 xpseudo[i] = sqrt(dist1/dist2);
06595 ypseudo[i] = sqrt(dist3/dist2);
06596 }
06597
06598 cpl_table_set_invalid(slits, "xpseudo", 0);
06599 cpl_table_set_invalid(slits, "xpseudo", nslits-1);
06600 cpl_table_set_invalid(slits, "ypseudo", 0);
06601 cpl_table_set_invalid(slits, "ypseudo", nslits-1);
06602
06603 cpl_table_duplicate_column(maskslits, "xpseudo", maskslits, "xcenter");
06604 cpl_table_duplicate_column(maskslits, "ypseudo", maskslits, "ycenter");
06605
06606 xcenter = cpl_table_get_data_double(maskslits, "xcenter");
06607 ycenter = cpl_table_get_data_double(maskslits, "ycenter");
06608 xmpseudo = cpl_table_get_data_double(maskslits, "xpseudo");
06609 ympseudo = cpl_table_get_data_double(maskslits, "ypseudo");
06610
06611 for (i = 1; i < nmaskslits - 1; i++) {
06612 dist1 = (xcenter[i-1] - xcenter[i])*(xcenter[i-1] - xcenter[i])
06613 + (ycenter[i-1] - ycenter[i])*(ycenter[i-1] - ycenter[i]);
06614 dist2 = (xcenter[i-1] - xcenter[i+1])*(xcenter[i-1] - xcenter[i+1])
06615 + (ycenter[i-1] - ycenter[i+1])*(ycenter[i-1] - ycenter[i+1]);
06616 dist3 = (xcenter[i] - xcenter[i+1])*(xcenter[i] - xcenter[i+1])
06617 + (ycenter[i] - ycenter[i+1])*(ycenter[i] - ycenter[i+1]);
06618 xmpseudo[i] = sqrt(dist1/dist2);
06619 ympseudo[i] = sqrt(dist3/dist2);
06620 }
06621
06622 cpl_table_set_invalid(maskslits, "xpseudo", 0);
06623 cpl_table_set_invalid(maskslits, "xpseudo", nmaskslits-1);
06624 cpl_table_set_invalid(maskslits, "ypseudo", 0);
06625 cpl_table_set_invalid(maskslits, "ypseudo", nmaskslits-1);
06626
06627
06628
06629
06630
06631
06632
06633
06634
06635
06636
06637 if (cpl_table_has_column(slits, "slit_id"))
06638 cpl_table_erase_column(slits, "slit_id");
06639 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
06640 slit_id = cpl_table_get_data_int(maskslits, "slit_id");
06641
06642 for (i = 1; i < nmaskslits - 1; i++) {
06643 in_sradius = 0;
06644 mindist = (xmpseudo[i] - xpseudo[1]) * (xmpseudo[i] - xpseudo[1])
06645 + (ympseudo[i] - ypseudo[1]) * (ympseudo[i] - ypseudo[1]);
06646 minpos = 1;
06647 if (mindist < sradius*sradius)
06648 in_sradius++;
06649 for (j = 2; j < nslits - 1; j++) {
06650 dist = (xmpseudo[i] - xpseudo[j]) * (xmpseudo[i] - xpseudo[j])
06651 + (ympseudo[i] - ypseudo[j]) * (ympseudo[i] - ypseudo[j]);
06652 if (dist < sradius*sradius)
06653 in_sradius++;
06654 if (in_sradius > 1)
06655 break;
06656 if (mindist > dist) {
06657 mindist = dist;
06658 minpos = j;
06659 }
06660 }
06661
06662 mindist = sqrt(mindist);
06663
06664 if (mindist < sradius && in_sradius == 1) {
06665 cpl_table_set_int(slits, "slit_id", minpos-1, slit_id[i-1]);
06666 cpl_table_set_int(slits, "slit_id", minpos, slit_id[i]);
06667 cpl_table_set_int(slits, "slit_id", minpos+1, slit_id[i+1]);
06668 }
06669 }
06670
06671
06672
06673
06674
06675
06676
06677 found_slits = nslits - cpl_table_count_invalid(slits, "slit_id");
06678
06679 if (found_slits < 3) {
06680 cpl_msg_warning(func, "Too few preliminarily identified slits: "
06681 "%d out of %d", found_slits, nslits);
06682 if (nslits == nmaskslits) {
06683 cpl_msg_warning(func, "(this is not an error, it could be caused "
06684 "by a mask with regularly located slits)");
06685 cpl_msg_warning(func, "The detected slits positions are left "
06686 "unchanged");
06687
06688
06689
06690
06691
06692
06693
06694
06695 cpl_table_erase_column(slits, "slit_id");
06696 cpl_table_erase_column(slits, "xpseudo");
06697 cpl_table_erase_column(slits, "ypseudo");
06698 positions = cpl_table_duplicate(slits);
06699 cpl_table_erase_column(slits, "xcenter");
06700 cpl_table_erase_column(slits, "ycenter");
06701
06702 cpl_table_erase_column(maskslits, "xpseudo");
06703 cpl_table_erase_column(maskslits, "ypseudo");
06704 cpl_table_duplicate_column(positions, "xmtop",
06705 maskslits, "xtop");
06706 cpl_table_duplicate_column(positions, "ymtop",
06707 maskslits, "ytop");
06708 cpl_table_duplicate_column(positions, "xmbottom",
06709 maskslits, "xbottom");
06710 cpl_table_duplicate_column(positions, "ymbottom",
06711 maskslits, "ybottom");
06712 cpl_table_duplicate_column(positions, "xmcenter",
06713 maskslits, "xcenter");
06714 cpl_table_duplicate_column(positions, "ymcenter",
06715 maskslits, "ycenter");
06716 cpl_table_duplicate_column(positions, "slit_id",
06717 maskslits, "slit_id");
06718 cpl_table_erase_column(maskslits, "xcenter");
06719 cpl_table_erase_column(maskslits, "ycenter");
06720 return positions;
06721 }
06722 else {
06723 cpl_table_erase_column(slits, "slit_id");
06724 cpl_table_erase_column(slits, "xpseudo");
06725 cpl_table_erase_column(slits, "ypseudo");
06726 positions = cpl_table_duplicate(slits);
06727 cpl_table_erase_column(slits, "xcenter");
06728 cpl_table_erase_column(slits, "ycenter");
06729 cpl_msg_warning(func, "(the failure could be caused "
06730 "by a mask with regularly located slits)");
06731 return NULL;
06732 }
06733 }
06734 else {
06735 cpl_msg_info(func, "Preliminarily identified slits: %d out of %d "
06736 "candidates (%d expected)", found_slits, nslits,
06737 nmaskslits);
06738 }
06739
06740
06741
06742
06743
06744
06745
06746
06747 positions = cpl_table_new(found_slits);
06748 cpl_table_new_column(positions, "slit_id", CPL_TYPE_INT);
06749 cpl_table_new_column(positions, "xtop", CPL_TYPE_DOUBLE);
06750 cpl_table_new_column(positions, "ytop", CPL_TYPE_DOUBLE);
06751 cpl_table_new_column(positions, "xbottom", CPL_TYPE_DOUBLE);
06752 cpl_table_new_column(positions, "ybottom", CPL_TYPE_DOUBLE);
06753 cpl_table_new_column(positions, "xcenter", CPL_TYPE_DOUBLE);
06754 cpl_table_new_column(positions, "ycenter", CPL_TYPE_DOUBLE);
06755 cpl_table_new_column(positions, "xmtop", CPL_TYPE_DOUBLE);
06756 cpl_table_new_column(positions, "ymtop", CPL_TYPE_DOUBLE);
06757 cpl_table_new_column(positions, "xmbottom", CPL_TYPE_DOUBLE);
06758 cpl_table_new_column(positions, "ymbottom", CPL_TYPE_DOUBLE);
06759 cpl_table_new_column(positions, "xmcenter", CPL_TYPE_DOUBLE);
06760 cpl_table_new_column(positions, "ymcenter", CPL_TYPE_DOUBLE);
06761 cpl_table_new_column(positions, "good", CPL_TYPE_INT);
06762 cpl_table_fill_column_window_int(positions, "good", 0, found_slits, 0);
06763
06764 slit_id = cpl_table_get_data_int (slits, "slit_id");
06765 xtop = cpl_table_get_data_double(slits, "xtop");
06766 ytop = cpl_table_get_data_double(slits, "ytop");
06767 xbottom = cpl_table_get_data_double(slits, "xbottom");
06768 ybottom = cpl_table_get_data_double(slits, "ybottom");
06769 xcenter = cpl_table_get_data_double(slits, "xcenter");
06770 ycenter = cpl_table_get_data_double(slits, "ycenter");
06771
06772 mslit_id = cpl_table_get_data_int (maskslits, "slit_id");
06773 xmtop = cpl_table_get_data_double(maskslits, "xtop");
06774 ymtop = cpl_table_get_data_double(maskslits, "ytop");
06775 xmbottom = cpl_table_get_data_double(maskslits, "xbottom");
06776 ymbottom = cpl_table_get_data_double(maskslits, "ybottom");
06777 xmcenter = cpl_table_get_data_double(maskslits, "xcenter");
06778 ymcenter = cpl_table_get_data_double(maskslits, "ycenter");
06779
06780
06781
06782
06783
06784
06785
06786
06787 k = 0;
06788 cpl_table_fill_invalid_int(slits, "slit_id", 0);
06789 for (i = 0; i < nmaskslits; i++) {
06790 for (j = 0; j < nslits; j++) {
06791 if (slit_id[j] == 0)
06792 continue;
06793 if (mslit_id[i] == slit_id[j]) {
06794 cpl_table_set_int (positions, "slit_id", k, slit_id[j]);
06795
06796 cpl_table_set_double(positions, "xtop", k, xtop[j]);
06797 cpl_table_set_double(positions, "ytop", k, ytop[j]);
06798 cpl_table_set_double(positions, "xbottom", k, xbottom[j]);
06799 cpl_table_set_double(positions, "ybottom", k, ybottom[j]);
06800 cpl_table_set_double(positions, "xcenter", k, xcenter[j]);
06801 cpl_table_set_double(positions, "ycenter", k, ycenter[j]);
06802
06803 cpl_table_set_double(positions, "xmtop", k, xmtop[i]);
06804 cpl_table_set_double(positions, "ymtop", k, ymtop[i]);
06805 cpl_table_set_double(positions, "xmbottom", k, xmbottom[i]);
06806 cpl_table_set_double(positions, "ymbottom", k, ymbottom[i]);
06807 cpl_table_set_double(positions, "xmcenter", k, xmcenter[i]);
06808 cpl_table_set_double(positions, "ymcenter", k, ymcenter[i]);
06809
06810 k++;
06811
06812 break;
06813 }
06814 }
06815 }
06816
06817 found_slits = k;
06818
06819 cpl_table_erase_column(slits, "slit_id");
06820 cpl_table_erase_column(slits, "xpseudo");
06821 cpl_table_erase_column(slits, "ypseudo");
06822 cpl_table_erase_column(slits, "xcenter");
06823 cpl_table_erase_column(slits, "ycenter");
06824 cpl_table_erase_column(maskslits, "xpseudo");
06825 cpl_table_erase_column(maskslits, "ypseudo");
06826 cpl_table_erase_column(maskslits, "xcenter");
06827 cpl_table_erase_column(maskslits, "ycenter");
06828
06829
06830
06831
06832
06833
06834
06835
06836
06837 ytop = cpl_table_get_data_double(positions, "ytop");
06838 ybottom = cpl_table_get_data_double(positions, "ybottom");
06839 xcenter = cpl_table_get_data_double(positions, "xcenter");
06840 ycenter = cpl_table_get_data_double(positions, "ycenter");
06841 xmcenter = cpl_table_get_data_double(positions, "xmcenter");
06842 ymcenter = cpl_table_get_data_double(positions, "ymcenter");
06843
06844 scales = cpl_vector_new(found_slits - 1);
06845 dscale = cpl_vector_get_data(scales);
06846 angles = cpl_vector_new(found_slits - 1);
06847 dangle = cpl_vector_get_data(angles);
06848
06849 for (i = 1; i < found_slits; i++) {
06850 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
06851 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
06852 dist2 = (xmcenter[i-1] - xmcenter[i]) * (xmcenter[i-1] - xmcenter[i])
06853 + (ymcenter[i-1] - ymcenter[i]) * (ymcenter[i-1] - ymcenter[i]);
06854 dscale[i-1] = sqrt(dist1/dist2);
06855 dangle[i-1] = atan2(ycenter[i-1] - ycenter[i],
06856 xcenter[i-1] - xcenter[i])
06857 - atan2(ymcenter[i-1] - ymcenter[i],
06858 xmcenter[i-1] - xmcenter[i]);
06859 dangle[i-1] *= 180;
06860 dangle[i-1] /= pi;
06861 }
06862
06863 minscale = cpl_vector_get_min(scales);
06864 scale = cpl_vector_get_median_const(scales);
06865 maxscale = cpl_vector_get_max(scales);
06866
06867 minangle = cpl_vector_get_min(angles);
06868 angle = cpl_vector_get_median_const(angles);
06869 maxangle = cpl_vector_get_max(angles);
06870
06871 cpl_msg_info(func, "Median platescale: %f pixel/mm", scale);
06872 cpl_msg_info(func, "Minmax platescale: %f, %f pixel/mm",
06873 minscale, maxscale);
06874
06875 cpl_msg_info(func, "Median rotation: %f degrees", angle);
06876 cpl_msg_info(func, "Minmax rotation: %f, %f degrees",
06877 minangle, maxangle);
06878
06879 good = cpl_table_get_data_int(positions, "good");
06880
06881 good[0] = good[found_slits - 1] = 1;
06882 for (i = 1; i < found_slits; i++) {
06883 if (fabs((dscale[i-1] - scale)/scale) < 0.10
06884 && fabs(dangle[i-1] - angle) < 2) {
06885 good[i-1]++;
06886 good[i]++;
06887 }
06888 }
06889
06890 for (i = 0; i < found_slits; i++) {
06891 if (good[i] < 2)
06892 good[i] = 0;
06893 else
06894 good[i] = 1;
06895 }
06896
06897
06898
06899
06900
06901
06902
06903
06904
06905
06906
06907
06908
06909
06910
06911
06912
06913
06914
06915
06916
06917
06918
06919
06920
06921
06922
06923
06924
06925
06926
06927
06928
06929
06930 cpl_vector_delete(scales);
06931 cpl_vector_delete(angles);
06932
06933 cpl_table_and_selected_int(positions, "good", CPL_EQUAL_TO, 0);
06934 cpl_table_erase_selected(positions);
06935 cpl_table_erase_column(positions, "good");
06936 found_slits = cpl_table_get_nrow(positions);
06937
06938 if (found_slits < 4) {
06939
06940
06941
06942
06943
06944
06945
06946 cpl_msg_warning(func, "Too few safely identified slits: %d out of %d "
06947 "candidates (%d expected). Process will continue "
06948 "using the detected CCD slits positions", found_slits,
06949 nslits, nmaskslits);
06950 cpl_table_delete(positions);
06951 return NULL;
06952 }
06953 else {
06954 cpl_msg_info(func, "Safely identified slits: %d out of %d "
06955 "candidates\n(%d expected)", found_slits, nslits,
06956 nmaskslits);
06957 }
06958
06959
06960
06961
06962
06963
06964
06965
06966 xpos = cpl_vector_wrap(found_slits,
06967 cpl_table_get_data_double(positions, "xcenter"));
06968 ypos = cpl_vector_wrap(found_slits,
06969 cpl_table_get_data_double(positions, "ycenter"));
06970 xmpos = cpl_vector_wrap(found_slits,
06971 cpl_table_get_data_double(positions, "xmcenter"));
06972 ympos = cpl_vector_wrap(found_slits,
06973 cpl_table_get_data_double(positions, "ymcenter"));
06974 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
06975
06976 if (found_slits < 10)
06977 degree = 1;
06978 else
06979 degree = 2;
06980
06981 xpoly = cpl_polynomial_fit_2d_create(mpos, xpos, degree, &xmse);
06982 if (xpoly != NULL)
06983 ypoly = cpl_polynomial_fit_2d_create(mpos, ypos, degree, &ymse);
06984 cpl_bivector_unwrap_vectors(mpos);
06985 cpl_vector_unwrap(xpos);
06986 cpl_vector_unwrap(ypos);
06987 cpl_vector_unwrap(xmpos);
06988 cpl_vector_unwrap(ympos);
06989 if (ypoly == NULL) {
06990 if (found_slits == nmaskslits) {
06991 cpl_msg_warning(func, "Fit failure: the accuracy of the "
06992 "identified slits positions is not improved.");
06993
06994
06995
06996
06997
06998
06999
07000
07001
07002 } else {
07003 cpl_msg_info(func, "Fit failure: not all slits have been "
07004 "identified. Process will continue using "
07005 "the detected CCD slits positions");
07006 }
07007
07008 cpl_polynomial_delete(xpoly);
07009 return positions;
07010 }
07011
07012 cpl_msg_info(func, "Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
07013 sqrt(xmse), sqrt(ymse));
07014
07015 if (global) {
07016 write_global_distortion(global, 0, xpoly);
07017 write_global_distortion(global, 7, ypoly);
07018 }
07019
07020
07021
07022
07023
07024
07025 cpl_table_delete(positions);
07026
07027 positions = cpl_table_duplicate(maskslits);
07028 cpl_table_duplicate_column(positions, "xmtop", positions, "xtop");
07029 cpl_table_duplicate_column(positions, "ymtop", positions, "ytop");
07030 cpl_table_duplicate_column(positions, "xmbottom", positions, "xbottom");
07031 cpl_table_duplicate_column(positions, "ymbottom", positions, "ybottom");
07032
07033 point = cpl_vector_new(2);
07034 dpoint = cpl_vector_get_data(point);
07035
07036 for (i = 0; i < nmaskslits; i++) {
07037 dpoint[0] = cpl_table_get_double(positions, "xmtop", i, NULL);
07038 dpoint[1] = cpl_table_get_double(positions, "ymtop", i, NULL);
07039 cpl_table_set_double(positions, "xtop", i,
07040 cpl_polynomial_eval(xpoly, point));
07041 cpl_table_set_double(positions, "ytop", i,
07042 cpl_polynomial_eval(ypoly, point));
07043 dpoint[0] = cpl_table_get_double(positions, "xmbottom", i, NULL);
07044 dpoint[1] = cpl_table_get_double(positions, "ymbottom", i, NULL);
07045 cpl_table_set_double(positions, "xbottom", i,
07046 cpl_polynomial_eval(xpoly, point));
07047 cpl_table_set_double(positions, "ybottom", i,
07048 cpl_polynomial_eval(ypoly, point));
07049 }
07050
07051 cpl_vector_delete(point);
07052 cpl_polynomial_delete(xpoly);
07053 cpl_polynomial_delete(ypoly);
07054
07055 cpl_table_erase_column(positions, "xmtop");
07056 cpl_table_erase_column(positions, "ymtop");
07057 cpl_table_erase_column(positions, "xmbottom");
07058 cpl_table_erase_column(positions, "ymbottom");
07059
07060 if (nmaskslits > nslits)
07061 cpl_msg_info(func, "Finally identified slits: %d out of %d expected\n"
07062 "(%d recovered)", nmaskslits, nmaskslits, nmaskslits - nslits);
07063 else if (nmaskslits < nslits)
07064 cpl_msg_info(func, "Finally identified slits: %d out of %d expected\n"
07065 "(%d rejected)", nmaskslits, nmaskslits, nslits - nmaskslits);
07066 else
07067 cpl_msg_info(func, "Finally identified slits: %d out of %d expected",
07068 nmaskslits, nmaskslits);
07069
07070 return positions;
07071 }
07072
07073
07115 cpl_table *mos_trace_flat(cpl_image *flat, cpl_table *slits, double reference,
07116 double blue, double red, double dispersion)
07117 {
07118
07119 const char *func = "mos_trace_flat";
07120
07121 cpl_image *gradient;
07122 cpl_image *sgradient;
07123 float *dgradient;
07124 float level = 500;
07125 cpl_vector *row;
07126 cpl_vector *srow;
07127 cpl_vector **peaks;
07128 double *peak;
07129 int *slit_id;
07130 float *g;
07131 double *r;
07132 double *xtop;
07133 double *ytop;
07134 double *xbottom;
07135 double *ybottom;
07136 double min, dist;
07137 double sradius;
07138 double tolerance;
07139 double start_y, prev_y;
07140 int minpos;
07141 int nslits;
07142 int nrows;
07143 int step = 10;
07144 int filtbox = 15;
07145 int nx, ny, npix;
07146 int pos, ypos;
07147 int npeaks;
07148 int pixel_above, pixel_below;
07149 int i, j, k, l;
07150 char trace_id[MAX_COLNAME];
07151
07152 cpl_table *traces;
07153
07154
07155 if (flat == NULL || slits == NULL) {
07156 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07157 return NULL;
07158 }
07159
07160 if (dispersion <= 0.0) {
07161 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07162 return NULL;
07163 }
07164
07165 if (red - blue < dispersion) {
07166 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07167 return NULL;
07168 }
07169
07170
07171
07172
07173
07174
07175 nslits = cpl_table_get_nrow(slits);
07176 if (1 != cpl_table_has_column(slits, "slit_id")) {
07177 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
07178 for (i = 0; i < nslits; i++)
07179 cpl_table_set_int(slits, "slit_id", i, -(i+1));
07180 }
07181
07182 slit_id = cpl_table_get_data_int(slits, "slit_id");
07183
07184 nx = cpl_image_get_size_x(flat);
07185 ny = cpl_image_get_size_y(flat);
07186 npix = nx * ny;
07187
07188 gradient = cpl_image_duplicate(flat);
07189 dgradient = cpl_image_get_data_float(gradient);
07190
07191 for (i = 0; i < ny - 1; i++) {
07192 k = i * nx;
07193 for (j = 0; j < nx; j++) {
07194 l = k + j;
07195 dgradient[l] = fabs(dgradient[l] - dgradient[l + nx]);
07196 }
07197 }
07198
07199 npix--;
07200 for (j = 0; j < nx; j++)
07201 dgradient[npix - j] = 0.0;
07202
07203 cpl_image_turn(gradient, -1);
07204 nx = cpl_image_get_size_x(gradient);
07205 ny = cpl_image_get_size_y(gradient);
07206 sgradient = mos_image_vertical_median_filter(gradient,
07207 filtbox, 0, ny, 0, step);
07208 cpl_image_delete(gradient);
07209
07210
07211
07212
07213
07214
07215 dgradient = cpl_image_get_data_float(sgradient);
07216
07217 for (i = 1; i <= ny; i += step) {
07218 row = cpl_vector_new_from_image_row(sgradient, i);
07219 srow = cpl_vector_filter_median_create(row, filtbox);
07220 cpl_vector_subtract(row, srow);
07221 cpl_vector_delete(srow);
07222 g = dgradient + (i-1)*nx;
07223 r = cpl_vector_get_data(row);
07224 for (j = 0; j < nx; j++)
07225 g[j] = r[j];
07226 cpl_vector_delete(row);
07227 }
07228
07229
07230
07231
07232
07233
07234
07235 mos_rotate_slits(slits, 1, nx, ny);
07236 xtop = cpl_table_get_data_double(slits, "xtop");
07237 ytop = cpl_table_get_data_double(slits, "ytop");
07238 xbottom = cpl_table_get_data_double(slits, "xbottom");
07239 ybottom = cpl_table_get_data_double(slits, "ybottom");
07240
07241
07242
07243
07244
07245
07246
07247 peaks = cpl_calloc(ny, sizeof(cpl_vector *));
07248
07249 for (i = 0; i < ny; i += step) {
07250 g = dgradient + i*nx;
07251 peaks[i] = mos_peak_candidates(g, nx, level, 1.0);
07252
07253
07254
07255 if (peaks[i])
07256 cpl_vector_subtract_scalar(peaks[i], 0.5);
07257
07258 }
07259
07260 cpl_image_delete(sgradient);
07261
07262
07263
07264
07265
07266
07267
07268
07269
07270 sradius = 5.0;
07271
07272
07273
07274
07275
07276
07277
07278
07279 tolerance = 0.9;
07280
07281
07282
07283
07284
07285
07286 pixel_above = (red - reference) / dispersion;
07287 pixel_below = (reference - blue) / dispersion;
07288
07289
07290
07291
07292
07293
07294 nrows = (ny-1)/step + 1;
07295 traces = cpl_table_new(nrows);
07296 cpl_table_new_column(traces, "x", CPL_TYPE_DOUBLE);
07297 cpl_table_set_column_unit(traces, "x", "pixel");
07298 for (i = 0, j = 0; i < ny; i += step, j++)
07299 cpl_table_set(traces, "x", j, i);
07300
07301 for (i = 0; i < nslits; i++) {
07302
07303
07304
07305
07306
07307 ypos = ytop[i];
07308
07309 if (ypos < 0)
07310 ypos = 0;
07311 if (ypos >= ny)
07312 ypos = ny - 1;
07313
07314 pos = ypos / step;
07315 pos *= step;
07316
07317
07318
07319
07320
07321 if (peaks[pos]) {
07322 peak = cpl_vector_get_data(peaks[pos]);
07323 npeaks = cpl_vector_get_size(peaks[pos]);
07324
07325 min = fabs(peak[0] - xtop[i]);
07326 minpos = 0;
07327 for (j = 1; j < npeaks; j++) {
07328 dist = fabs(peak[j] - xtop[i]);
07329 if (min > dist) {
07330 min = dist;
07331 minpos = j;
07332 }
07333 }
07334 }
07335 else {
07336 npeaks = 0;
07337 }
07338
07339 snprintf(trace_id, MAX_COLNAME, "t%d", slit_id[i]);
07340 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
07341
07342 if (min > sradius || npeaks == 0) {
07343 cpl_msg_warning(func, "Cannot find spectrum edge for "
07344 "top (or left) end of slit %d", slit_id[i]);
07345 }
07346 else {
07347
07348
07349
07350
07351
07352
07353
07354
07355
07356 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
07357 start_y = peak[minpos];
07358
07359
07360
07361
07362
07363 prev_y = start_y;
07364
07365 for (j = pos + step; j < ny; j += step) {
07366 if (j - pos > pixel_above)
07367 break;
07368 if (peaks[j]) {
07369 peak = cpl_vector_get_data(peaks[j]);
07370 npeaks = cpl_vector_get_size(peaks[j]);
07371 min = fabs(peak[0] - prev_y);
07372 minpos = 0;
07373 for (k = 1; k < npeaks; k++) {
07374 dist = fabs(peak[k] - prev_y);
07375 if (min > dist) {
07376 min = dist;
07377 minpos = k;
07378 }
07379 }
07380 if (min < tolerance) {
07381 cpl_table_set(traces, trace_id, j/step,
07382 nx - peak[minpos]);
07383 prev_y = peak[minpos];
07384 }
07385 }
07386 }
07387
07388
07389
07390
07391
07392 prev_y = start_y;
07393
07394 for (j = pos - step; j >= 0; j -= step) {
07395 if (pos - j > pixel_below)
07396 break;
07397 if (peaks[j]) {
07398 peak = cpl_vector_get_data(peaks[j]);
07399 npeaks = cpl_vector_get_size(peaks[j]);
07400 min = fabs(peak[0] - prev_y);
07401 minpos = 0;
07402 for (k = 1; k < npeaks; k++) {
07403 dist = fabs(peak[k] - prev_y);
07404 if (min > dist) {
07405 min = dist;
07406 minpos = k;
07407 }
07408 }
07409 if (min < tolerance) {
07410 cpl_table_set(traces, trace_id, j/step,
07411 nx - peak[minpos]);
07412 prev_y = peak[minpos];
07413 }
07414 }
07415 }
07416 }
07417
07418
07419
07420
07421
07422
07423 if (peaks[pos]) {
07424 peak = cpl_vector_get_data(peaks[pos]);
07425 npeaks = cpl_vector_get_size(peaks[pos]);
07426
07427 min = fabs(peak[0] - xbottom[i]);
07428 minpos = 0;
07429 for (j = 1; j < npeaks; j++) {
07430 dist = fabs(peak[j] - xbottom[i]);
07431 if (min > dist) {
07432 min = dist;
07433 minpos = j;
07434 }
07435 }
07436 }
07437 else {
07438 npeaks = 0;
07439 }
07440
07441 snprintf(trace_id, MAX_COLNAME, "b%d", slit_id[i]);
07442 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
07443
07444 if (min > sradius || npeaks == 0) {
07445 cpl_msg_warning(func, "Cannot find spectrum edge for "
07446 "bottom (or right) end of slit %d", slit_id[i]);
07447 }
07448 else {
07449
07450 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
07451 start_y = peak[minpos];
07452
07453
07454
07455
07456
07457 prev_y = start_y;
07458
07459 for (j = pos + step; j < ny; j += step) {
07460 if (j - pos > pixel_above)
07461 break;
07462 if (peaks[j]) {
07463 peak = cpl_vector_get_data(peaks[j]);
07464 npeaks = cpl_vector_get_size(peaks[j]);
07465 min = fabs(peak[0] - prev_y);
07466 minpos = 0;
07467 for (k = 1; k < npeaks; k++) {
07468 dist = fabs(peak[k] - prev_y);
07469 if (min > dist) {
07470 min = dist;
07471 minpos = k;
07472 }
07473 }
07474 if (min < tolerance) {
07475 cpl_table_set(traces, trace_id, j/step,
07476 nx - peak[minpos]);
07477 prev_y = peak[minpos];
07478 }
07479 }
07480 }
07481
07482
07483
07484
07485
07486 prev_y = start_y;
07487
07488 for (j = pos - step; j >= 0; j -= step) {
07489 if (pos - j > pixel_below)
07490 break;
07491 if (peaks[j]) {
07492 peak = cpl_vector_get_data(peaks[j]);
07493 npeaks = cpl_vector_get_size(peaks[j]);
07494 min = fabs(peak[0] - prev_y);
07495 minpos = 0;
07496 for (k = 1; k < npeaks; k++) {
07497 dist = fabs(peak[k] - prev_y);
07498 if (min > dist) {
07499 min = dist;
07500 minpos = k;
07501 }
07502 }
07503 if (min < tolerance) {
07504 cpl_table_set(traces, trace_id, j/step,
07505 nx - peak[minpos]);
07506 prev_y = peak[minpos];
07507 }
07508 }
07509 }
07510 }
07511
07512 }
07513
07514 for (i = 0; i < ny; i += step)
07515 cpl_vector_delete(peaks[i]);
07516 cpl_free(peaks);
07517
07518
07519
07520
07521
07522 mos_rotate_slits(slits, -1, ny, nx);
07523
07524 return traces;
07525
07526 }
07527
07528
07549 cpl_table *mos_poly_trace(cpl_table *slits, cpl_table *traces, int order)
07550 {
07551 const char *func = "mos_poly_trace";
07552
07553 cpl_table *polytraces;
07554 cpl_table *dummy;
07555 cpl_vector *x;
07556 cpl_vector *trace;
07557 cpl_polynomial *polytrace;
07558 char trace_id[MAX_COLNAME];
07559 char trace_res[MAX_COLNAME];
07560 char trace_mod[MAX_COLNAME];
07561 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
07562
07563 double *xdata;
07564 int *slit_id;
07565 int nslits;
07566 int nrows;
07567 int npoints;
07568 int i, j, k;
07569
07570
07571 if (traces == NULL || slits == NULL) {
07572 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07573 return NULL;
07574 }
07575
07576 if (order > 5) {
07577 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07578 return NULL;
07579 }
07580
07581 nrows = cpl_table_get_nrow(traces);
07582 xdata = cpl_table_get_data_double(traces, "x");
07583 nslits = cpl_table_get_nrow(slits);
07584 slit_id = cpl_table_get_data_int(slits, "slit_id");
07585
07586 polytraces = cpl_table_new(2*nslits);
07587 cpl_table_new_column(polytraces, "slit_id", CPL_TYPE_INT);
07588 for (i = 0; i <= order; i++)
07589 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
07590
07591 for (i = 0; i < nslits; i++) {
07592 for (j = 0; j < 2; j++) {
07593
07594 if (j) {
07595 snprintf(trace_id, MAX_COLNAME, "b%d", slit_id[i]);
07596 snprintf(trace_res, MAX_COLNAME, "b%d_res", slit_id[i]);
07597 snprintf(trace_mod, MAX_COLNAME, "b%d_mod", slit_id[i]);
07598 }
07599 else {
07600 snprintf(trace_id, MAX_COLNAME, "t%d", slit_id[i]);
07601 snprintf(trace_res, MAX_COLNAME, "t%d_res", slit_id[i]);
07602 snprintf(trace_mod, MAX_COLNAME, "t%d_mod", slit_id[i]);
07603 }
07604
07605 cpl_table_set_int(polytraces, "slit_id", 2*i+j, slit_id[i]);
07606
07607
07608
07609
07610
07611
07612 dummy = cpl_table_new(nrows);
07613 cpl_table_duplicate_column(dummy, "x", traces, "x");
07614 cpl_table_duplicate_column(dummy, trace_id, traces, trace_id);
07615 npoints = nrows - cpl_table_count_invalid(dummy, trace_id);
07616 if (npoints < 2 * order) {
07617 cpl_table_delete(dummy);
07618 continue;
07619 }
07620 cpl_table_erase_invalid(dummy);
07621 x = cpl_vector_wrap(npoints,
07622 cpl_table_get_data_double(dummy, "x"));
07623 trace = cpl_vector_wrap(npoints,
07624 cpl_table_get_data_double(dummy, trace_id));
07625 polytrace = cpl_polynomial_fit_1d_create(x, trace, order, NULL);
07626 cpl_vector_unwrap(x);
07627 cpl_vector_unwrap(trace);
07628 cpl_table_delete(dummy);
07629
07630
07631
07632
07633
07634
07635
07636 k = 2;
07637 if (cpl_polynomial_get_coeff(polytrace, &k) > 1.E-5) {
07638 cpl_polynomial_delete(polytrace);
07639 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
07640 cpl_table_duplicate_column(traces, trace_res, traces,
07641 trace_mod);
07642 if (j)
07643 cpl_msg_warning(func, "Exclude bad curvature solution "
07644 "for bottom (right) edge of slit %d", slit_id[i]);
07645 else
07646 cpl_msg_warning(func, "Exclude bad curvature solution "
07647 "for top (left) edge of slit %d", slit_id[i]);
07648 continue;
07649 }
07650
07651
07652
07653
07654
07655
07656 for (k = 0; k <= order; k++)
07657 cpl_table_set_double(polytraces, clab[k], 2*i+j,
07658 cpl_polynomial_get_coeff(polytrace, &k));
07659
07660
07661
07662
07663
07664 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
07665 cpl_table_set_column_unit(traces, trace_mod, "pixel");
07666
07667 for (k = 0; k < nrows; k++) {
07668 cpl_table_set_double(traces, trace_mod, k,
07669 cpl_polynomial_eval_1d(polytrace, xdata[k], NULL));
07670 }
07671
07672 cpl_polynomial_delete(polytrace);
07673
07674 cpl_table_duplicate_column(traces, trace_res, traces, trace_mod);
07675 cpl_table_subtract_columns(traces, trace_res, trace_id);
07676 cpl_table_multiply_scalar(traces, trace_res, -1.0);
07677
07678 }
07679 }
07680
07681 return polytraces;
07682
07683 }
07684
07685
07709 cpl_error_code mos_global_trace(cpl_table *slits, cpl_table *polytraces,
07710 int mode)
07711 {
07712 const char *func = "mos_global_trace";
07713
07714 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
07715
07716 cpl_table *table;
07717 cpl_vector *c0;
07718 cpl_vector *cn;
07719 cpl_bivector *list;
07720
07721
07722
07723
07724 double *offset;
07725 double rms, q, m;
07726
07727 int order, nrows, nslits;
07728 int i, j;
07729
07730
07731 if (polytraces == NULL) {
07732 cpl_msg_error(func, "Missing spectral curvature table");
07733 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07734 }
07735
07736 if (slits == NULL) {
07737 cpl_msg_error(func, "Missing slits positions table");
07738 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07739 }
07740
07741 nslits = cpl_table_get_nrow(slits);
07742
07743 table = cpl_table_duplicate(polytraces);
07744 cpl_table_erase_invalid(table);
07745
07746 nrows = cpl_table_get_nrow(table);
07747
07748 if (nrows < 4) {
07749 cpl_msg_warning(func, "Too few successful spectral curvature tracings "
07750 "(%d): the determination of a global curvature model "
07751 "failed", nrows);
07752 return CPL_ERROR_NONE;
07753 }
07754
07755 order = cpl_table_get_ncol(polytraces) - 2;
07756
07757 for (i = 0; i <= order; i++) {
07758 if (!cpl_table_has_column(table, clab[i])) {
07759 cpl_msg_error(func, "Wrong spectral curvature table");
07760 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07761 }
07762 }
07763
07764
07765
07766
07767
07768
07769 for (i = 0; i < nslits; i++) {
07770 if (!cpl_table_is_valid(polytraces, clab[0], 2*i)) {
07771 cpl_table_set_double(polytraces, clab[0], 2*i,
07772 cpl_table_get_double(slits, "ytop", i, NULL));
07773 }
07774 if (!cpl_table_is_valid(polytraces, clab[0], 2*i+1)) {
07775 cpl_table_set_double(polytraces, clab[0], 2*i+1,
07776 cpl_table_get_double(slits, "ybottom", i, NULL));
07777 }
07778 }
07779
07780 offset = cpl_table_get_data_double(polytraces, clab[0]);
07781
07782
07783
07784
07785
07786
07787 c0 = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[0]));
07788
07789 for (i = 1; i <= order; i++) {
07790 cn = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[i]));
07791 list = cpl_bivector_wrap_vectors(c0, cn);
07792 robustLinearFit(list, &q, &m, &rms);
07793
07794
07795
07796 for (j = 0; j < 2*nslits; j++) {
07797 if (mode == 1)
07798 if (cpl_table_is_valid(polytraces, clab[i], j))
07799 continue;
07800 cpl_table_set_double(polytraces, clab[i], j, offset[j]*m + q);
07801
07802
07803
07804
07805 }
07806 cpl_bivector_unwrap_vectors(list);
07807
07808
07809
07810 cpl_vector_unwrap(cn);
07811 }
07812
07813 cpl_vector_unwrap(c0);
07814 cpl_table_delete(table);
07815
07816 return CPL_ERROR_NONE;
07817
07818 }
07819
07820
07890 cpl_image *mos_spatial_calibration(cpl_image *spectra, cpl_table *slits,
07891 cpl_table *polytraces, double reference,
07892 double blue, double red, double dispersion,
07893 int flux, cpl_image *calibration)
07894 {
07895 const char *func = "mos_spatial_calibration";
07896
07897 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
07898
07899 cpl_polynomial *polytop;
07900 cpl_polynomial *polybot;
07901 cpl_image **exslit;
07902 cpl_image *resampled;
07903 float *data;
07904 float *sdata;
07905 float *xdata;
07906 double vtop, vbot, value;
07907 double top, bot;
07908 double coeff;
07909 double ytop, ybot;
07910 double ypos, yfra;
07911 double factor;
07912 int yint, ysize, yprev;
07913 int nslits;
07914 int npseudo;
07915 int *slit_id;
07916 int *length;
07917 int nx, ny;
07918 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
07919 int missing_top, missing_bot;
07920 int null;
07921 int order;
07922 int i, j, k;
07923
07924 int create_position = 1;
07925
07926
07927 if (spectra == NULL || slits == NULL || polytraces == NULL) {
07928 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07929 return NULL;
07930 }
07931
07932 if (dispersion <= 0.0) {
07933 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07934 return NULL;
07935 }
07936
07937 if (red - blue < dispersion) {
07938 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07939 return NULL;
07940 }
07941
07942 nx = cpl_image_get_size_x(spectra);
07943 ny = cpl_image_get_size_y(spectra);
07944 sdata = cpl_image_get_data(spectra);
07945 if (calibration)
07946 data = cpl_image_get_data(calibration);
07947
07948 if (cpl_table_has_column(slits, "position"))
07949 create_position = 0;
07950
07951 if (create_position) {
07952 cpl_table_new_column(slits, "position", CPL_TYPE_INT);
07953 cpl_table_new_column(slits, "length", CPL_TYPE_INT);
07954 cpl_table_set_column_unit(slits, "position", "pixel");
07955 cpl_table_set_column_unit(slits, "length", "pixel");
07956 }
07957 else
07958 length = cpl_table_get_data_int(slits, "length");
07959
07960 nslits = cpl_table_get_nrow(slits);
07961 slit_id = cpl_table_get_data_int(slits, "slit_id");
07962 order = cpl_table_get_ncol(polytraces) - 2;
07963
07964
07965
07966
07967
07968
07969 pixel_above = (red - reference) / dispersion;
07970 pixel_below = (reference - blue) / dispersion;
07971
07972 exslit = cpl_calloc(nslits, sizeof(cpl_image *));
07973
07974 for (i = 0; i < nslits; i++) {
07975
07976 if (create_position == 0)
07977 if (length[i] == 0)
07978 continue;
07979
07980
07981
07982
07983
07984
07985
07986
07987
07988
07989
07990
07991 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
07992
07993 start_pixel = refpixel - pixel_below;
07994 if (start_pixel < 0)
07995 start_pixel = 0;
07996
07997 end_pixel = refpixel + pixel_above;
07998 if (end_pixel > nx)
07999 end_pixel = nx;
08000
08001
08002
08003
08004
08005
08006 missing_top = 0;
08007 polytop = cpl_polynomial_new(1);
08008 for (k = 0; k <= order; k++) {
08009 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
08010 if (null) {
08011 cpl_polynomial_delete(polytop);
08012 missing_top = 1;
08013 break;
08014 }
08015 cpl_polynomial_set_coeff(polytop, &k, coeff);
08016 }
08017
08018 missing_bot = 0;
08019 polybot = cpl_polynomial_new(1);
08020 for (k = 0; k <= order; k++) {
08021 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
08022 if (null) {
08023 cpl_polynomial_delete(polybot);
08024 missing_bot = 1;
08025 break;
08026 }
08027 cpl_polynomial_set_coeff(polybot, &k, coeff);
08028 }
08029
08030 if (missing_top && missing_bot) {
08031 cpl_msg_warning(func, "Spatial calibration, slit %d was not "
08032 "traced: no extraction!",
08033 slit_id[i]);
08034 continue;
08035 }
08036
08037
08038
08039
08040
08041
08042
08043 if (missing_top) {
08044 cpl_msg_warning(func, "Upper edge of slit %d was not traced: "
08045 "the spectral curvature of the lower edge "
08046 "is used instead.", slit_id[i]);
08047 polytop = cpl_polynomial_duplicate(polybot);
08048 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
08049 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
08050 k = 0;
08051 coeff = cpl_polynomial_get_coeff(polybot, &k);
08052 coeff += ytop - ybot;
08053 cpl_polynomial_set_coeff(polytop, &k, coeff);
08054 }
08055
08056 if (missing_bot) {
08057 cpl_msg_warning(func, "Lower edge of slit %d was not traced: "
08058 "the spectral curvature of the upper edge "
08059 "is used instead.", slit_id[i]);
08060 polybot = cpl_polynomial_duplicate(polytop);
08061 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
08062 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
08063 k = 0;
08064 coeff = cpl_polynomial_get_coeff(polytop, &k);
08065 coeff -= ytop - ybot;
08066 cpl_polynomial_set_coeff(polybot, &k, coeff);
08067 }
08068
08069
08070
08071
08072
08073 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
08074 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
08075 npseudo = ceil(top-bot) + 1;
08076
08077 if (npseudo < 1) {
08078 cpl_polynomial_delete(polytop);
08079 cpl_polynomial_delete(polybot);
08080 cpl_msg_warning(func, "Slit %d was badly traced: no extraction!",
08081 slit_id[i]);
08082 continue;
08083 }
08084
08085 exslit[i] = cpl_image_new(nx, npseudo+1, CPL_TYPE_FLOAT);
08086 xdata = cpl_image_get_data(exslit[i]);
08087
08088
08089
08090
08091
08092 for (j = start_pixel; j < end_pixel; j++) {
08093 top = cpl_polynomial_eval_1d(polytop, j, NULL);
08094 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
08095 factor = (top-bot)/npseudo;
08096 for (k = 0; k <= npseudo; k++) {
08097 ypos = top - k*factor;
08098 yint = ypos;
08099 yfra = ypos - yint;
08100 if (yint >= 0 && yint < ny-1) {
08101 vtop = sdata[j + nx*yint];
08102 vbot = sdata[j + nx*(yint+1)];
08103 value = vtop*(1-yfra) + vbot*yfra;
08104 if (flux)
08105 value *= factor;
08106 xdata[j + nx*(npseudo-k)] = value;
08107 if (calibration) {
08108 data[j + nx*yint] = (top-yint)/factor;
08109 if (k) {
08110
08111
08112
08113
08114
08115
08116
08117 if (yprev - yint > 1) {
08118 data[j + nx*(yint+1)] = (top-yint-1)/factor;
08119 }
08120 }
08121 }
08122 }
08123 yprev = yint;
08124 }
08125 }
08126 cpl_polynomial_delete(polytop);
08127 cpl_polynomial_delete(polybot);
08128 }
08129
08130
08131
08132
08133
08134 ysize = 0;
08135 for (i = 0; i < nslits; i++)
08136 if (exslit[i])
08137 ysize += cpl_image_get_size_y(exslit[i]);
08138
08139 resampled = cpl_image_new(nx, ysize, CPL_TYPE_FLOAT);
08140
08141 yint = -1;
08142 for (i = 0; i < nslits; i++) {
08143 if (exslit[i]) {
08144 yint += cpl_image_get_size_y(exslit[i]);
08145 cpl_image_copy(resampled, exslit[i], 1, ysize - yint);
08146 if (create_position) {
08147 cpl_table_set_int(slits, "position", i, ysize - yint - 1);
08148 cpl_table_set_int(slits, "length", i,
08149 cpl_image_get_size_y(exslit[i]));
08150 }
08151 cpl_image_delete(exslit[i]);
08152 }
08153 else if (create_position) {
08154 cpl_table_set_int(slits, "position", i, -1);
08155 cpl_table_set_int(slits, "length", i, 0);
08156 }
08157 }
08158
08159
08160
08161
08162
08163
08164
08165
08166
08167
08168
08169
08170
08171
08172
08173
08174
08175 cpl_free(exslit);
08176
08177 return resampled;
08178
08179 }
08180
08181
08288 cpl_image *mos_wavelength_calibration_final(cpl_image *image, cpl_table *slits,
08289 cpl_vector *lines,
08290 double dispersion, float level,
08291 int sradius, int order,
08292 double reject, double refwave,
08293 double *wavestart, double *waveend,
08294 int *nlines, double *error,
08295 cpl_table *idscoeff,
08296 cpl_image *calibration,
08297 cpl_image *residuals,
08298 cpl_table *restable)
08299 {
08300
08301 const char *func = "mos_wavelength_calibration_final";
08302
08303 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
08304
08305
08306 double tolerance = 20.0;
08307 int step = 10;
08308
08309 char name[MAX_COLNAME];
08310
08311 cpl_image *resampled;
08312 cpl_bivector *output;
08313 cpl_vector *wavel;
08314 cpl_vector *peaks;
08315 cpl_polynomial *ids;
08316 cpl_polynomial *lin;
08317 cpl_polynomial *fguess;
08318 cpl_table *coeff;
08319 double ids_err;
08320 double max_disp, min_disp;
08321 double *line;
08322 double firstLambda, lastLambda, lambda;
08323 double wave, pixe, value;
08324 double c;
08325 float *sdata;
08326 float *rdata;
08327 float *idata;
08328 float *ddata;
08329 float v1, v2, vi;
08330 float fpixel;
08331 int *length;
08332 int pixstart, pixend;
08333 int row_top, row_bot;
08334 int extrapolation;
08335 int nref;
08336 int nslits;
08337 int nfits;
08338 int nl, nx, ny, pixel;
08339 int countLines, usedLines;
08340 int uorder;
08341 int missing;
08342 int null;
08343 int width, uradius;
08344 int i, j, k, s;
08345
08346
08347 if (dispersion == 0.0) {
08348 cpl_msg_error(func, "The expected dispersion (A/pixel) must be given");
08349 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08350 return NULL;
08351 }
08352
08353 if (dispersion < 0.0) {
08354 cpl_msg_error(func, "The expected dispersion must be positive");
08355 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08356 return NULL;
08357 }
08358
08359 if (idscoeff == NULL) {
08360 cpl_msg_error(func, "A preallocated IDS coeff table must be given");
08361 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08362 return NULL;
08363 }
08364
08365 max_disp = dispersion + dispersion * tolerance / 100;
08366 min_disp = dispersion - dispersion * tolerance / 100;
08367
08368 if (order < 1) {
08369 cpl_msg_error(func, "The order of the fitting polynomial "
08370 "must be at least 1");
08371 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08372 return NULL;
08373 }
08374
08375 if (image == NULL || lines == NULL) {
08376 cpl_msg_error(func, "Both spectral exposure and reference line "
08377 "catalog are required in input");
08378 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08379 return NULL;
08380 }
08381
08382 nx = cpl_image_get_size_x(image);
08383 ny = cpl_image_get_size_y(image);
08384 sdata = cpl_image_get_data_float(image);
08385
08386 nref = cpl_vector_get_size(lines);
08387 line = cpl_vector_get_data(lines);
08388
08389 if (*wavestart < 1.0 && *waveend < 1.0) {
08390 firstLambda = line[0];
08391 lastLambda = line[nref-1];
08392 extrapolation = (lastLambda - firstLambda) / 10;
08393 firstLambda -= extrapolation;
08394 lastLambda += extrapolation;
08395 *wavestart = firstLambda;
08396 *waveend = lastLambda;
08397 }
08398 else {
08399 firstLambda = *wavestart;
08400 lastLambda = *waveend;
08401 }
08402
08403 nl = (lastLambda - firstLambda) / dispersion;
08404 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
08405 rdata = cpl_image_get_data_float(resampled);
08406
08407
08408
08409
08410
08411 for (j = 0; j <= order; j++)
08412 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
08413
08414 if (calibration)
08415 idata = cpl_image_get_data_float(calibration);
08416
08417 if (residuals)
08418 ddata = cpl_image_get_data_float(residuals);
08419
08420 if (restable) {
08421 cpl_table_set_size(restable, nref);
08422 cpl_table_new_column(restable, "wavelength", CPL_TYPE_DOUBLE);
08423 cpl_table_copy_data_double(restable, "wavelength", line);
08424 for (i = 0; i < ny; i += step) {
08425 snprintf(name, MAX_COLNAME, "r%d", i);
08426 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
08427 snprintf(name, MAX_COLNAME, "d%d", i);
08428 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
08429 snprintf(name, MAX_COLNAME, "p%d", i);
08430 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
08431 }
08432 }
08433
08434
08435
08436
08437
08438
08439 nslits = cpl_table_get_nrow(slits);
08440 length = cpl_table_get_data_int(slits, "length");
08441
08442 row_top = ny;
08443 for (s = 0; s < nslits; s++) {
08444
08445 if (length[s] == 0)
08446 continue;
08447
08448
08449
08450
08451
08452
08453 row_bot = cpl_table_get_int(slits, "position", s, NULL);
08454
08455 if (sradius > 0) {
08456
08457
08458
08459
08460
08461
08462
08463
08464
08465 coeff = cpl_table_new(row_top - row_bot);
08466 for (j = 0; j <= order; j++)
08467 cpl_table_new_column(coeff, clab[j], CPL_TYPE_DOUBLE);
08468 }
08469
08470
08471
08472
08473
08474
08475 for (i = row_bot; i < row_top; i++) {
08476 width = mos_lines_width(sdata + i*nx, nx);
08477 if (width < 5)
08478 width = 5;
08479 peaks = mos_peak_candidates(sdata + i*nx, nx, level, width);
08480 if (peaks) {
08481 peaks = mos_refine_peaks(sdata + i*nx, nx, peaks, width);
08482 }
08483 if (peaks) {
08484 output = mos_identify_peaks(peaks, lines,
08485 min_disp, max_disp, 0.05);
08486 if (output) {
08487 countLines = cpl_bivector_get_size(output);
08488 if (countLines < 4) {
08489 cpl_bivector_delete(output);
08490 cpl_vector_delete(peaks);
08491 if (nlines)
08492 nlines[i] = 0;
08493 if (error)
08494 error[i] = 0.0;
08495 continue;
08496 }
08497
08498
08499
08500
08501
08502 wavel = cpl_bivector_get_y(output);
08503 cpl_vector_subtract_scalar(wavel, refwave);
08504
08505 uorder = countLines / 2 - 1;
08506 if (uorder > order)
08507 uorder = order;
08508
08509 ids = mos_poly_wav2pix(output, uorder, reject,
08510 2 * (uorder + 1), &usedLines,
08511 &ids_err);
08512
08513 if (ids == NULL) {
08514 cpl_bivector_delete(output);
08515 cpl_vector_delete(peaks);
08516 if (nlines)
08517 nlines[i] = 0;
08518 if (error)
08519 error[i] = 0.0;
08520 cpl_error_reset();
08521 continue;
08522 }
08523
08524 if (sradius > 0) {
08525 for (k = 0; k <= order; k++) {
08526 if (k > uorder) {
08527 cpl_table_set_double(coeff, clab[k],
08528 i - row_bot, 0.0);
08529 }
08530 else {
08531 cpl_table_set_double(coeff, clab[k],
08532 i - row_bot, cpl_polynomial_get_coeff(ids, &k));
08533 }
08534 }
08535 }
08536
08537 if (calibration) {
08538 pixstart = cpl_polynomial_eval_1d(ids,
08539 cpl_bivector_get_y_data(output)[0],
08540 NULL);
08541 pixend = cpl_polynomial_eval_1d(ids,
08542 cpl_bivector_get_y_data(output)[countLines-1],
08543 NULL);
08544 extrapolation = (pixend - pixstart) / 5;
08545 pixstart -= extrapolation;
08546 pixend += extrapolation;
08547 if (pixstart < 0)
08548 pixstart = 0;
08549 if (pixend > nx)
08550 pixend = nx;
08551
08552 for (j = pixstart; j < pixend; j++) {
08553 (idata + i*nx)[j] = mos_eval_dds(ids,
08554 firstLambda, lastLambda, refwave, j);
08555 }
08556 }
08557
08558
08559
08560
08561
08562 if (residuals || (restable && !(i%step))) {
08563 if (restable && !(i%step)) {
08564 lin = cpl_polynomial_new(1);
08565 for (k = 0; k < 2; k++)
08566 cpl_polynomial_set_coeff(lin, &k,
08567 cpl_polynomial_get_coeff(ids, &k));
08568 }
08569 for (j = 0; j < countLines; j++) {
08570 pixe = cpl_bivector_get_x_data(output)[j];
08571 wave = cpl_bivector_get_y_data(output)[j];
08572 value = pixe
08573 - cpl_polynomial_eval_1d(ids, wave, NULL);
08574 if (residuals) {
08575 pixel = pixe + 0.5;
08576 (ddata + i*nx)[pixel] = value;
08577 }
08578 if (restable && !(i%step)) {
08579 for (k = 0; k < nref; k++) {
08580 if (fabs(line[k]-refwave-wave) < 0.1) {
08581 snprintf(name, MAX_COLNAME,
08582 "r%d", i);
08583 cpl_table_set_double(restable, name,
08584 k, value);
08585 value = pixe
08586 - cpl_polynomial_eval_1d(lin,
08587 wave, NULL);
08588 snprintf(name, MAX_COLNAME,
08589 "d%d", i);
08590 cpl_table_set_double(restable, name,
08591 k, value);
08592 snprintf(name, MAX_COLNAME,
08593 "p%d", i);
08594 cpl_table_set_double(restable, name,
08595 k, pixe);
08596 break;
08597 }
08598 }
08599 }
08600 }
08601 if (restable && !(i%step)) {
08602 cpl_polynomial_delete(lin);
08603 }
08604
08605
08606
08607
08608
08609
08610
08611
08612
08613
08614
08615 }
08616
08617
08618
08619
08620
08621
08622
08623
08624 if (nlines)
08625 nlines[i] = usedLines;
08626 if (error)
08627 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
08628
08629 for (k = 0; k <= order; k++) {
08630 if (k > uorder) {
08631 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
08632 }
08633 else {
08634 cpl_table_set_double(idscoeff, clab[k], i,
08635 cpl_polynomial_get_coeff(ids, &k));
08636 }
08637 }
08638
08639 cpl_polynomial_delete(ids);
08640 cpl_bivector_delete(output);
08641 }
08642 cpl_vector_delete(peaks);
08643 }
08644 }
08645
08646
08647 if (sradius > 0) {
08648
08649
08650
08651
08652
08653 nfits = row_top - row_bot - cpl_table_count_invalid(coeff, clab[0]);
08654
08655 if (nfits) {
08656
08657
08658
08659
08660
08661 fguess = cpl_polynomial_new(1);
08662
08663 for (k = 0; k <= order; k++) {
08664 c = cpl_table_get_column_median(coeff, clab[k]);
08665 cpl_polynomial_set_coeff(fguess, &k, c);
08666 }
08667
08668 for (i = row_bot; i < row_top; i++) {
08669
08670
08671
08672
08673
08674 width = mos_lines_width(sdata + i*nx, nx);
08675 if (width > sradius) {
08676 uradius = width;
08677 }
08678 else {
08679 uradius = sradius;
08680 }
08681
08682 output = mos_find_peaks(sdata + i*nx, nx, lines,
08683 fguess, refwave, uradius);
08684
08685 if (output == NULL) {
08686 cpl_error_reset();
08687 continue;
08688 }
08689
08690 countLines = cpl_bivector_get_size(output);
08691
08692 if (countLines < 4) {
08693 cpl_bivector_delete(output);
08694 continue;
08695 }
08696
08697
08698
08699
08700
08701 wavel = cpl_bivector_get_y(output);
08702 cpl_vector_subtract_scalar(wavel, refwave);
08703
08704 uorder = countLines / 2 - 1;
08705 if (uorder > order)
08706 uorder = order;
08707
08708 ids = mos_poly_wav2pix(output, uorder, reject,
08709 2 * (uorder + 1), &usedLines,
08710 &ids_err);
08711
08712 if (ids == NULL) {
08713 cpl_error_reset();
08714 cpl_bivector_delete(output);
08715 continue;
08716 }
08717
08718 if (nlines)
08719 nlines[i] = usedLines;
08720 if (error)
08721 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
08722
08723 if (calibration) {
08724 pixstart = cpl_polynomial_eval_1d(ids,
08725 cpl_bivector_get_y_data(output)[0],
08726 NULL);
08727 pixend = cpl_polynomial_eval_1d(ids,
08728 cpl_bivector_get_y_data(output)[countLines-1],
08729 NULL);
08730 extrapolation = (pixend - pixstart) / 5;
08731 pixstart -= extrapolation;
08732 pixend += extrapolation;
08733 if (pixstart < 0)
08734 pixstart = 0;
08735 if (pixend > nx)
08736 pixend = nx;
08737
08738 for (j = pixstart; j < pixend; j++) {
08739 (idata + i*nx)[j] = mos_eval_dds(ids,
08740 firstLambda, lastLambda, refwave, j);
08741 }
08742 }
08743
08744
08745
08746
08747
08748 if (residuals || (restable && !(i%step))) {
08749 if (restable && !(i%step)) {
08750 lin = cpl_polynomial_new(1);
08751 for (k = 0; k < 2; k++)
08752 cpl_polynomial_set_coeff(lin, &k,
08753 cpl_polynomial_get_coeff(ids, &k));
08754 }
08755 for (j = 0; j < countLines; j++) {
08756 pixe = cpl_bivector_get_x_data(output)[j];
08757 wave = cpl_bivector_get_y_data(output)[j];
08758 value = pixe
08759 - cpl_polynomial_eval_1d(ids, wave, NULL);
08760 if (residuals) {
08761 pixel = pixe + 0.5;
08762 (ddata + i*nx)[pixel] = value;
08763 }
08764 if (restable && !(i%step)) {
08765 for (k = 0; k < nref; k++) {
08766 if (fabs(line[k]-refwave-wave) < 0.1) {
08767 snprintf(name, MAX_COLNAME,
08768 "r%d", i);
08769 cpl_table_set_double(restable, name,
08770 k, value);
08771 value = pixe
08772 - cpl_polynomial_eval_1d(lin,
08773 wave, NULL);
08774 snprintf(name, MAX_COLNAME,
08775 "d%d", i);
08776 cpl_table_set_double(restable, name,
08777 k, value);
08778 snprintf(name, MAX_COLNAME,
08779 "p%d", i);
08780 cpl_table_set_double(restable, name,
08781 k, pixe);
08782 break;
08783 }
08784 }
08785 }
08786 }
08787 if (restable && !(i%step)) {
08788 cpl_polynomial_delete(lin);
08789 }
08790
08791
08792
08793
08794
08795
08796
08797
08798
08799
08800
08801 }
08802
08803 for (k = 0; k <= order; k++) {
08804 if (k > uorder) {
08805 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
08806 }
08807 else {
08808 cpl_table_set_double(idscoeff, clab[k], i,
08809 cpl_polynomial_get_coeff(ids, &k));
08810 }
08811 }
08812
08813 cpl_bivector_delete(output);
08814 cpl_polynomial_delete(ids);
08815
08816 }
08817
08818 cpl_polynomial_delete(fguess);
08819 }
08820
08821 cpl_table_delete(coeff);
08822
08823 }
08824
08825 row_top = row_bot;
08826
08827 }
08828
08829
08830
08831
08832
08833
08834
08835
08836
08837 for (i = 0; i < ny; i++) {
08838
08839 missing = 0;
08840 ids = cpl_polynomial_new(1);
08841 for (k = 0; k <= order; k++) {
08842 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
08843 if (null) {
08844 cpl_polynomial_delete(ids);
08845 missing = 1;
08846 break;
08847 }
08848 cpl_polynomial_set_coeff(ids, &k, c);
08849 }
08850 if (missing)
08851 continue;
08852
08853 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
08854 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
08855 if (pixstart < 0)
08856 pixstart = 0;
08857 if (pixend > nx)
08858 pixend = nx;
08859
08860
08861
08862
08863
08864 for (j = 0; j < nl; j++) {
08865 lambda = firstLambda + j * dispersion;
08866 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave, NULL);
08867 pixel = fpixel;
08868 if (pixel >= 0 && pixel < nx-1) {
08869 v1 = (sdata + i*nx)[pixel];
08870 v2 = (sdata + i*nx)[pixel+1];
08871 vi = v1 + (v2-v1)*(fpixel-pixel);
08872 (rdata + i*nl)[j] = vi;
08873 }
08874 }
08875
08876 cpl_polynomial_delete(ids);
08877 }
08878
08879 return resampled;
08880 }
08881
08882
08909 cpl_image *mos_wavelength_calibration(cpl_image *image, double refwave,
08910 double firstLambda, double lastLambda,
08911 double dispersion, cpl_table *idscoeff,
08912 int flux)
08913 {
08914
08915 const char *func = "mos_wavelength_calibration";
08916
08917 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
08918
08919
08920 cpl_image *resampled;
08921 cpl_polynomial *ids;
08922 double pixel_per_lambda;
08923 double lambda;
08924 double c;
08925 float *sdata;
08926 float *rdata;
08927 float v0, v1, v2, v3, vi;
08928 float fpixel;
08929 int order;
08930 int pixstart, pixend;
08931 int nl, nx, ny, pixel;
08932 int missing;
08933 int null;
08934 int i, j, k;
08935
08936
08937 if (dispersion <= 0.0) {
08938 cpl_msg_error(func, "The resampling step must be positive");
08939 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08940 return NULL;
08941 }
08942
08943 if (lastLambda - firstLambda < dispersion) {
08944 cpl_msg_error(func, "Invalid spectral range: %.2f to %.2f",
08945 firstLambda, lastLambda);
08946 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08947 return NULL;
08948 }
08949
08950 if (idscoeff == NULL) {
08951 cpl_msg_error(func, "An IDS coeff table must be given");
08952 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08953 return NULL;
08954 }
08955
08956 if (image == NULL) {
08957 cpl_msg_error(func, "A scientific spectral image must be given");
08958 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08959 return NULL;
08960 }
08961
08962 nx = cpl_image_get_size_x(image);
08963 ny = cpl_image_get_size_y(image);
08964 sdata = cpl_image_get_data_float(image);
08965
08966 nl = (lastLambda - firstLambda) / dispersion;
08967 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
08968 rdata = cpl_image_get_data_float(resampled);
08969
08970 order = 0;
08971 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
08972 ++order;
08973 --order;
08974
08975 for (i = 0; i < ny; i++) {
08976
08977 missing = 0;
08978 ids = cpl_polynomial_new(1);
08979 for (k = 0; k <= order; k++) {
08980 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
08981 if (null) {
08982 cpl_polynomial_delete(ids);
08983 missing = 1;
08984 break;
08985 }
08986 cpl_polynomial_set_coeff(ids, &k, c);
08987 }
08988 if (missing)
08989 continue;
08990
08991 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
08992 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
08993 if (pixstart < 0)
08994 pixstart = 0;
08995 if (pixend > nx)
08996 pixend = nx;
08997
08998
08999
09000
09001
09002 for (j = 0; j < nl; j++) {
09003 lambda = firstLambda + j * dispersion;
09004 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
09005 &pixel_per_lambda);
09006
09007
09008
09009
09010
09011
09012
09013 pixel = fpixel;
09014 if (pixel >= 1 && pixel < nx-2) {
09015 v0 = (sdata + i*nx)[pixel-1];
09016 v1 = (sdata + i*nx)[pixel];
09017 v2 = (sdata + i*nx)[pixel+1];
09018 v3 = (sdata + i*nx)[pixel+2];
09019 vi = (fpixel-pixel)*(fpixel-pixel)*(v3 - v2 - v1 + v0)
09020 + (fpixel-pixel)*(3*v2 - v3 - v1 - v0)
09021 + 2*v1;
09022 vi /= 2;
09023 if (v1 > v2) {
09024 if (vi > v1) {
09025 vi = v1;
09026 }
09027 else if (vi < v2) {
09028 vi = v2;
09029 }
09030 }
09031 else {
09032 if (vi > v2) {
09033 vi = v2;
09034 }
09035 else if (vi < v1) {
09036 vi = v1;
09037 }
09038 }
09039 if (flux)
09040 vi *= dispersion * pixel_per_lambda;
09041 (rdata + i*nl)[j] = vi;
09042 }
09043 else if (pixel >= 0 && pixel < nx-1) {
09044 v1 = (sdata + i*nx)[pixel];
09045 v2 = (sdata + i*nx)[pixel+1];
09046 vi = v1 + (v2-v1)*(fpixel-pixel);
09047 if (flux)
09048 vi *= dispersion * pixel_per_lambda;
09049 (rdata + i*nl)[j] = vi;
09050 }
09051 }
09052
09053 cpl_polynomial_delete(ids);
09054 }
09055
09056 return resampled;
09057 }
09058
09059
09126 cpl_table *mos_wavelength_align(cpl_image *image, cpl_table *slits,
09127 double refwave, double firstLambda,
09128 double lastLambda, cpl_table *idscoeff,
09129 cpl_vector *skylines, int highres, int order,
09130 cpl_image *calibration, int sradius)
09131 {
09132 const char *func = "mos_wavelength_align";
09133
09134 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
09135
09136 double *line;
09137 double *data;
09138 double expPos, offset;
09139 double c;
09140 double lambda1, lambda2;
09141 double rms;
09142 float pos;
09143 float *sdata;
09144 float *cdata;
09145 int *idata;
09146 int startPos, endPos;
09147 int window = 2*sradius + 1;
09148 int nlines;
09149 int nslits;
09150 int npoints;
09151 int nrows;
09152 int nx, ny;
09153 int xlow, ylow, xhig, yhig;
09154 int idsorder, uorder;
09155 int *slit_id;
09156 int *position;
09157 int *length;
09158 int missing;
09159 int null;
09160 int i, j, k;
09161
09162 char offname[MAX_COLNAME];
09163 char name[MAX_COLNAME];
09164
09165 cpl_polynomial *ids;
09166 cpl_polynomial *polycorr;
09167 cpl_image *exslit;
09168 cpl_image *sky;
09169 cpl_table *offsets;
09170 cpl_table *dummy;
09171 cpl_vector *wave;
09172 cpl_vector *offs;
09173
09174
09175 if (idscoeff == NULL) {
09176 cpl_msg_error(func, "An IDS coeff table must be given");
09177 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09178 return NULL;
09179 }
09180
09181 if (image == NULL) {
09182 cpl_msg_error(func, "A scientific spectral image must be given");
09183 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09184 return NULL;
09185 }
09186
09187 if (slits == NULL) {
09188 cpl_msg_error(func, "A slit position table must be given");
09189 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09190 return NULL;
09191 }
09192
09193 if (skylines) {
09194 line = cpl_vector_get_data(skylines);
09195 nlines = cpl_vector_get_size(skylines);
09196 }
09197 else {
09198 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
09199 "given: using internal list of reference sky lines");
09200 if (highres) {
09201 line = default_lines_hi;
09202 nlines = sizeof(default_lines_hi) / sizeof(double);
09203 }
09204 else {
09205 line = default_lines_lo;
09206 nlines = sizeof(default_lines_lo) / sizeof(double);
09207 }
09208 }
09209
09210 if (calibration)
09211 cdata = cpl_image_get_data(calibration);
09212
09213 nx = cpl_image_get_size_x(image);
09214 ny = cpl_image_get_size_y(image);
09215
09216 nslits = cpl_table_get_nrow(slits);
09217 slit_id = cpl_table_get_data_int(slits, "slit_id");
09218 position = cpl_table_get_data_int(slits, "position");
09219 length = cpl_table_get_data_int(slits, "length");
09220
09221
09222
09223
09224
09225
09226 nrows = 0;
09227 for (i = 0; i < nlines; i++)
09228 if (line[i] > firstLambda && line[i] < lastLambda)
09229 nrows++;
09230
09231 offsets = cpl_table_new(nrows);
09232 cpl_table_new_column(offsets, "wave", CPL_TYPE_DOUBLE);
09233 cpl_table_set_column_unit(offsets, "wave", "Angstrom");
09234
09235 nrows = 0;
09236 for (i = 0; i < nlines; i++) {
09237 if (line[i] > firstLambda && line[i] < lastLambda) {
09238 cpl_table_set_double(offsets, "wave", nrows, line[i]);
09239 nrows++;
09240 }
09241 }
09242
09243
09244
09245
09246
09247 line = cpl_table_get_data_double(offsets, "wave");
09248 nlines = nrows;
09249
09250 idsorder = 0;
09251 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
09252 ++idsorder;
09253 --idsorder;
09254
09255 xlow = 1;
09256 xhig = nx;
09257 for (i = 0; i < nslits; i++) {
09258
09259 if (length[i] == 0)
09260 continue;
09261
09262 snprintf(offname, MAX_COLNAME, "offset%d", slit_id[i]);
09263 cpl_table_new_column(offsets, offname, CPL_TYPE_DOUBLE);
09264
09265
09266
09267
09268
09269
09270
09271
09272
09273
09274
09275 ylow = position[i] + 1;
09276 yhig = ylow + length[i] - 1;
09277
09278 exslit = cpl_image_extract(image, xlow, ylow, xhig, yhig);
09279 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
09280 sdata = cpl_image_get_data(sky);
09281
09282 cpl_image_delete(exslit);
09283
09284
09285
09286
09287
09288
09289 ylow--;
09290
09291
09292
09293
09294
09295
09296
09297 dummy = cpl_table_new(yhig - ylow);
09298 for (j = 0; j < nlines; j++) {
09299 snprintf(name, MAX_COLNAME, "%d", j);
09300 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
09301 }
09302
09303 for (j = ylow; j < yhig; j++) {
09304
09305
09306
09307
09308
09309 missing = 0;
09310 ids = cpl_polynomial_new(1);
09311 for (k = 0; k <= idsorder; k++) {
09312 c = cpl_table_get_double(idscoeff, clab[k], j, &null);
09313 if (null) {
09314 cpl_polynomial_delete(ids);
09315 missing = 1;
09316 break;
09317 }
09318 cpl_polynomial_set_coeff(ids, &k, c);
09319 }
09320 if (missing)
09321 continue;
09322
09323 for (k = 0; k < nlines; k++) {
09324 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
09325 startPos = expPos - sradius;
09326 endPos = startPos + window;
09327 if (startPos < 0 || endPos >= nx)
09328 continue;
09329
09330 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
09331 pos += startPos;
09332 offset = pos - expPos;
09333 snprintf(name, MAX_COLNAME, "%d", k);
09334 cpl_table_set_double(dummy, name, j - ylow, offset);
09335 }
09336 }
09337
09338 cpl_polynomial_delete(ids);
09339 }
09340
09341 cpl_image_delete(sky);
09342
09343 for (j = 0; j < nlines; j++) {
09344 snprintf(name, MAX_COLNAME, "%d", j);
09345 if (cpl_table_has_valid(dummy, name)) {
09346 offset = cpl_table_get_column_median(dummy, name);
09347 cpl_table_set_double(offsets, offname, j, offset);
09348 }
09349 }
09350
09351 cpl_table_delete(dummy);
09352
09353 }
09354
09355
09356
09357
09358
09359
09360
09361
09362 for (i = 0; i < nslits; i++) {
09363
09364 if (length[i] == 0)
09365 continue;
09366
09367 snprintf(offname, MAX_COLNAME, "offset%d", slit_id[i]);
09368
09369
09370
09371
09372
09373
09374 dummy = cpl_table_new(nlines);
09375 cpl_table_duplicate_column(dummy, "wave", offsets, "wave");
09376 cpl_table_duplicate_column(dummy, "offset", offsets, offname);
09377
09378 npoints = nlines - cpl_table_count_invalid(dummy, "offset");
09379 if (npoints == 0) {
09380 cpl_msg_warning(func, "No sky lines alignment was possible "
09381 "for slit ID=%d: no sky line found", slit_id[i]);
09382 cpl_table_delete(dummy);
09383 continue;
09384 }
09385
09386 uorder = order;
09387 if (npoints <= uorder) {
09388 uorder = npoints - 1;
09389 if (uorder) {
09390 cpl_msg_warning(func, "Just %d sky lines detected for slit "
09391 "ID=%d, while a polynomial order %d was "
09392 "requested. Using polynomial order %d for "
09393 "this slit!", npoints, slit_id[i], order,
09394 uorder);
09395 }
09396 else {
09397 cpl_msg_warning(func, "Just %d sky lines detected for slit "
09398 "ID=%d, while a polynomial order %d was "
09399 "requested. Computing a median offset for "
09400 "this slit!", npoints, slit_id[i], order);
09401 }
09402 }
09403
09404 cpl_table_erase_invalid(dummy);
09405
09406 if (uorder > 1) {
09407
09408
09409
09410
09411
09412 wave = cpl_vector_wrap(npoints,
09413 cpl_table_get_data_double(dummy, "wave"));
09414 offs = cpl_vector_wrap(npoints,
09415 cpl_table_get_data_double(dummy, "offset"));
09416
09417
09418
09419
09420
09421 cpl_vector_subtract_scalar(wave, refwave);
09422
09423 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
09424
09425 rms = sqrt(rms * (uorder + 1) / npoints);
09426
09427 cpl_vector_unwrap(wave);
09428 cpl_vector_unwrap(offs);
09429 cpl_table_delete(dummy);
09430
09431
09432
09433
09434
09435
09436 ylow = position[i];
09437 yhig = ylow + length[i];
09438
09439 for (j = 0; j <= uorder; j++) {
09440 data = cpl_table_get_data_double(idscoeff, clab[j]);
09441 c = cpl_polynomial_get_coeff(polycorr, &j);
09442 for (k = ylow; k < yhig; k++)
09443 data[k] += c;
09444 }
09445
09446 data = cpl_table_get_data_double(idscoeff, "error");
09447 for (k = ylow; k < yhig; k++)
09448 data[k] = sqrt(data[k]*data[k] + rms*rms);
09449
09450 idata = cpl_table_get_data_int(idscoeff, "nlines");
09451 for (k = ylow; k < yhig; k++)
09452 idata[k] = npoints;
09453
09454
09455
09456
09457
09458
09459 if (calibration) {
09460 for (j = ylow; j < yhig; j++) {
09461 for (k = 1; k < nx; k++) {
09462 lambda1 = cdata[k - 1 + j*nx];
09463 lambda2 = cdata[k + j*nx];
09464 if (lambda1 < 1.0 || lambda2 < 1.0)
09465 continue;
09466 offset = cpl_polynomial_eval_1d(polycorr,
09467 lambda1-refwave, NULL);
09468 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
09469 }
09470 }
09471 }
09472
09473 cpl_polynomial_delete(polycorr);
09474 }
09475 else if (uorder == 1) {
09476
09477
09478
09479
09480
09481 double q, m;
09482 cpl_bivector *list;
09483
09484
09485 wave = cpl_vector_wrap(npoints,
09486 cpl_table_get_data_double(dummy, "wave"));
09487 offs = cpl_vector_wrap(npoints,
09488 cpl_table_get_data_double(dummy, "offset"));
09489
09490 list = cpl_bivector_wrap_vectors(wave, offs);
09491
09492
09493
09494
09495
09496 cpl_vector_subtract_scalar(wave, refwave);
09497
09498 robustLinearFit(list, &q, &m, &rms);
09499
09500 rms = sqrt(rms * (uorder + 1) / npoints);
09501
09502 cpl_bivector_unwrap_vectors(list);
09503 cpl_vector_unwrap(wave);
09504 cpl_vector_unwrap(offs);
09505 cpl_table_delete(dummy);
09506
09507
09508
09509
09510
09511
09512 ylow = position[i];
09513 yhig = ylow + length[i];
09514
09515 for (j = 0; j <= uorder; j++) {
09516 data = cpl_table_get_data_double(idscoeff, clab[j]);
09517 if (j)
09518 c = m;
09519 else
09520 c = q;
09521 for (k = ylow; k < yhig; k++)
09522 data[k] += c;
09523 }
09524
09525 data = cpl_table_get_data_double(idscoeff, "error");
09526 for (k = ylow; k < yhig; k++)
09527 data[k] = sqrt(data[k]*data[k] + rms*rms);
09528
09529 idata = cpl_table_get_data_int(idscoeff, "nlines");
09530 for (k = ylow; k < yhig; k++)
09531 idata[k] = npoints;
09532
09533
09534
09535
09536
09537
09538 if (calibration) {
09539 for (j = ylow; j < yhig; j++) {
09540 for (k = 1; k < nx; k++) {
09541 lambda1 = cdata[k - 1 + j*nx];
09542 lambda2 = cdata[k + j*nx];
09543 if (lambda1 < 1.0 || lambda2 < 1.0)
09544 continue;
09545 offset = q + m*(lambda1-refwave);
09546 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
09547 }
09548 }
09549 }
09550 }
09551 else {
09552
09553
09554
09555
09556
09557 offs = cpl_vector_wrap(npoints,
09558 cpl_table_get_data_double(dummy, "offset"));
09559
09560 offset = cpl_vector_get_median_const(offs);
09561
09562 if (npoints > 1)
09563 rms = cpl_table_get_column_stdev(dummy, "offset");
09564 else
09565 rms = 0.0;
09566
09567 rms /= sqrt(npoints);
09568
09569 cpl_vector_unwrap(offs);
09570 cpl_table_delete(dummy);
09571
09572
09573
09574
09575
09576
09577 ylow = position[i];
09578 yhig = ylow + length[i];
09579
09580 data = cpl_table_get_data_double(idscoeff, clab[0]);
09581 for (k = ylow; k < yhig; k++)
09582 data[k] += offset;
09583
09584 data = cpl_table_get_data_double(idscoeff, "error");
09585 for (k = ylow; k < yhig; k++)
09586 data[k] = sqrt(data[k]*data[k] + rms*rms);
09587
09588 idata = cpl_table_get_data_int(idscoeff, "nlines");
09589 for (k = ylow; k < yhig; k++)
09590 idata[k] = npoints;
09591
09592
09593
09594
09595
09596
09597
09598 if (calibration) {
09599 for (j = ylow; j < yhig; j++) {
09600 for (k = 1; k < nx; k++) {
09601 lambda1 = cdata[k - 1 + j*nx];
09602 lambda2 = cdata[k + j*nx];
09603 if (lambda1 < 1.0 || lambda2 < 1.0)
09604 continue;
09605 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
09606 }
09607 }
09608 }
09609 }
09610 }
09611
09612 return offsets;
09613
09614 }
09615
09616
09678 cpl_table *mos_wavelength_align_lss(cpl_image *image, double refwave,
09679 double firstLambda, double lastLambda,
09680 cpl_table *idscoeff, cpl_vector *skylines,
09681 int highres, int order,
09682 cpl_image *calibration, int sradius)
09683 {
09684 const char *func = "mos_wavelength_align_lss";
09685
09686 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
09687
09688 double *line;
09689 double *data;
09690 double *wdata;
09691 double *odata;
09692 double expPos, offset;
09693 double c;
09694 double lambda1, lambda2;
09695 double rms;
09696 float pos;
09697 float *sdata;
09698 float *cdata;
09699 int *idata;
09700 int startPos, endPos;
09701 int window = 2*sradius + 1;
09702 int nlines;
09703 int npoints;
09704 int nrows;
09705 int nx, ny;
09706 int idsorder, uorder;
09707 int missing;
09708 int i, j, k;
09709
09710 char name[MAX_COLNAME];
09711 char fname[MAX_COLNAME];
09712
09713 cpl_polynomial *ids;
09714 cpl_polynomial *polycorr;
09715 cpl_table *offsets;
09716 cpl_table *fittable;
09717 cpl_table *dummy;
09718 cpl_vector *wave;
09719 cpl_vector *offs;
09720 cpl_vector *row;
09721
09722
09723 if (idscoeff == NULL) {
09724 cpl_msg_error(func, "An IDS coeff table must be given");
09725 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09726 return NULL;
09727 }
09728
09729 if (image == NULL) {
09730 cpl_msg_error(func, "A scientific spectral image must be given");
09731 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09732 return NULL;
09733 }
09734
09735 if (skylines) {
09736 line = cpl_vector_get_data(skylines);
09737 nlines = cpl_vector_get_size(skylines);
09738 }
09739 else {
09740 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
09741 "given: using internal list of reference sky lines");
09742 if (highres) {
09743 line = default_lines_hi;
09744 nlines = sizeof(default_lines_hi) / sizeof(double);
09745 }
09746 else {
09747 line = default_lines_lo;
09748 nlines = sizeof(default_lines_lo) / sizeof(double);
09749 }
09750 }
09751
09752 if (calibration)
09753 cdata = cpl_image_get_data(calibration);
09754
09755 nx = cpl_image_get_size_x(image);
09756 ny = cpl_image_get_size_y(image);
09757
09758 sdata = cpl_image_get_data(image);
09759
09760
09761
09762
09763
09764
09765
09766
09767
09768
09769 nrows = 0;
09770 for (i = 0; i < nlines; i++)
09771 if (line[i] > firstLambda && line[i] < lastLambda)
09772 nrows++;
09773
09774 offsets = cpl_table_new(nrows);
09775 cpl_table_new_column(offsets, "wave", CPL_TYPE_DOUBLE);
09776 cpl_table_set_column_unit(offsets, "wave", "Angstrom");
09777
09778 nrows = 0;
09779 for (i = 0; i < nlines; i++) {
09780 if (line[i] > firstLambda && line[i] < lastLambda) {
09781 cpl_table_set_double(offsets, "wave", nrows, line[i]);
09782 nrows++;
09783 }
09784 }
09785
09786
09787
09788
09789
09790 line = cpl_table_get_data_double(offsets, "wave");
09791 nlines = nrows;
09792
09793 idsorder = 0;
09794 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
09795 ++idsorder;
09796 --idsorder;
09797
09798
09799
09800
09801
09802
09803
09804 dummy = cpl_table_new(ny);
09805 for (j = 0; j < nlines; j++) {
09806 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
09807 snprintf(fname, MAX_COLNAME, "fit_%d", (int)line[j]);
09808 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
09809 cpl_table_new_column(dummy, fname, CPL_TYPE_DOUBLE);
09810 }
09811
09812 for (j = 0; j < ny; j++, sdata += nx) {
09813
09814
09815
09816
09817
09818 missing = 0;
09819 ids = cpl_polynomial_new(1);
09820 for (k = 0; k <= idsorder; k++) {
09821 c = cpl_table_get_double(idscoeff, clab[k], j, &missing);
09822 if (missing) {
09823 cpl_polynomial_delete(ids);
09824 break;
09825 }
09826 cpl_polynomial_set_coeff(ids, &k, c);
09827 }
09828 if (missing)
09829 continue;
09830
09831 for (k = 0; k < nlines; k++) {
09832 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
09833 startPos = expPos - sradius;
09834 endPos = startPos + window;
09835 if (startPos < 0 || endPos >= nx)
09836 continue;
09837
09838 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
09839 pos += startPos;
09840 offset = pos - expPos;
09841 snprintf(name, MAX_COLNAME, "off_%d", (int)line[k]);
09842 cpl_table_set_double(dummy, name, j, offset);
09843 }
09844 }
09845
09846 cpl_polynomial_delete(ids);
09847 }
09848
09849
09850
09851
09852
09853
09854
09855 for (j = 0; j < nlines; j++) {
09856 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
09857 snprintf(fname, MAX_COLNAME, "fit_%d", (int)line[j]);
09858 if (cpl_table_has_valid(dummy, name)) {
09859
09860
09861
09862
09863
09864
09865 double q, m;
09866 cpl_bivector *list;
09867
09868 fittable = cpl_table_new(ny);
09869 cpl_table_new_column(fittable, "row", CPL_TYPE_DOUBLE);
09870 cpl_table_set_column_unit(fittable, "row", "pixel");
09871 for (k = 0; k < ny; k++)
09872 cpl_table_set_double(fittable, "row", k, k);
09873 cpl_table_duplicate_column(fittable, "offset", dummy, name);
09874 npoints = ny - cpl_table_count_invalid(fittable, "offset");
09875 cpl_table_erase_invalid(fittable);
09876 row = cpl_vector_wrap(npoints,
09877 cpl_table_get_data_double(fittable, "row"));
09878 offs = cpl_vector_wrap(npoints,
09879 cpl_table_get_data_double(fittable, "offset"));
09880 list = cpl_bivector_wrap_vectors(row, offs);
09881 robustLinearFit(list, &q, &m, &rms);
09882 cpl_bivector_unwrap_vectors(list);
09883 cpl_vector_unwrap(row);
09884 cpl_vector_unwrap(offs);
09885 cpl_table_delete(fittable);
09886 for (k = 0; k < ny; k++)
09887 cpl_table_set_double(dummy, fname, k, q + m*k);
09888 }
09889 }
09890
09891
09892
09893
09894
09895
09896
09897
09898
09899
09900 for (i = 0; i < ny; i++) {
09901
09902 if (!cpl_table_is_valid(idscoeff, clab[0], i))
09903 continue;
09904
09905 npoints = 0;
09906 for (j = 0; j < nlines; j++) {
09907 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
09908 if (cpl_table_is_valid(dummy, name, i))
09909 npoints++;
09910 }
09911
09912 if (npoints == 0)
09913 continue;
09914
09915 uorder = order;
09916 if (npoints <= uorder)
09917 uorder = npoints - 1;
09918
09919 if (uorder > 1) {
09920
09921
09922
09923
09924
09925 wave = cpl_vector_new(npoints);
09926 wdata = cpl_vector_get_data(wave);
09927 offs = cpl_vector_new(npoints);
09928 odata = cpl_vector_get_data(offs);
09929
09930 npoints = 0;
09931 for (j = 0; j < nlines; j++) {
09932 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
09933 if (cpl_table_is_valid(dummy, name, i)) {
09934 wdata[npoints] = line[j] - refwave;
09935 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
09936 npoints++;
09937 }
09938 }
09939
09940 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
09941
09942 rms = sqrt(rms * (uorder + 1) / npoints);
09943
09944 cpl_vector_delete(wave);
09945 cpl_vector_delete(offs);
09946
09947
09948
09949
09950
09951
09952 for (j = 0; j <= uorder; j++) {
09953 data = cpl_table_get_data_double(idscoeff, clab[j]);
09954 c = cpl_polynomial_get_coeff(polycorr, &j);
09955 data[i] += c;
09956 }
09957
09958 data = cpl_table_get_data_double(idscoeff, "error");
09959 data[i] = sqrt(data[i]*data[i] + rms*rms);
09960
09961 idata = cpl_table_get_data_int(idscoeff, "nlines");
09962 idata[i] = npoints;
09963
09964
09965
09966
09967
09968
09969 if (calibration) {
09970 for (k = 1; k < nx; k++) {
09971 lambda1 = cdata[k - 1 + i*nx];
09972 lambda2 = cdata[k + i*nx];
09973 if (lambda1 < 1.0 || lambda2 < 1.0)
09974 continue;
09975 offset = cpl_polynomial_eval_1d(polycorr,
09976 lambda1-refwave, NULL);
09977 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
09978 }
09979 }
09980
09981 cpl_polynomial_delete(polycorr);
09982
09983 }
09984 else if (uorder == 1) {
09985
09986
09987
09988
09989
09990 cpl_bivector *list;
09991 double q, m;
09992
09993 wave = cpl_vector_new(npoints);
09994 wdata = cpl_vector_get_data(wave);
09995 offs = cpl_vector_new(npoints);
09996 odata = cpl_vector_get_data(offs);
09997
09998 npoints = 0;
09999 for (j = 0; j < nlines; j++) {
10000 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
10001 if (cpl_table_is_valid(dummy, name, i)) {
10002 wdata[npoints] = line[j] - refwave;
10003 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10004 npoints++;
10005 }
10006 }
10007
10008 list = cpl_bivector_wrap_vectors(wave, offs);
10009 robustLinearFit(list, &q, &m, &rms);
10010
10011 rms = sqrt(rms * (uorder + 1) / npoints);
10012
10013 cpl_bivector_unwrap_vectors(list);
10014 cpl_vector_delete(wave);
10015 cpl_vector_delete(offs);
10016
10017
10018
10019
10020
10021
10022 for (j = 0; j <= uorder; j++) {
10023 data = cpl_table_get_data_double(idscoeff, clab[j]);
10024 if (j)
10025 c = m;
10026 else
10027 c = q;
10028 data[i] += c;
10029 }
10030
10031 data = cpl_table_get_data_double(idscoeff, "error");
10032 data[i] = sqrt(data[i]*data[i] + rms*rms);
10033
10034 idata = cpl_table_get_data_int(idscoeff, "nlines");
10035 idata[i] = npoints;
10036
10037
10038
10039
10040
10041
10042 if (calibration) {
10043 for (k = 1; k < nx; k++) {
10044 lambda1 = cdata[k - 1 + i*nx];
10045 lambda2 = cdata[k + i*nx];
10046 if (lambda1 < 1.0 || lambda2 < 1.0)
10047 continue;
10048 offset = q + m*(lambda1-refwave);
10049 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10050 }
10051 }
10052 }
10053 else {
10054
10055
10056
10057
10058
10059 offs = cpl_vector_new(npoints);
10060 odata = cpl_vector_get_data(offs);
10061
10062 npoints = 0;
10063 for (j = 0; j < nlines; j++) {
10064 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
10065 if (cpl_table_is_valid(dummy, name, i)) {
10066 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10067 npoints++;
10068 }
10069 }
10070
10071 offset = cpl_vector_get_median_const(offs);
10072
10073 if (npoints > 1) {
10074 rms = cpl_vector_get_stdev(offs);
10075 }
10076 else if (npoints == 1) {
10077 snprintf(name, MAX_COLNAME, "off_%d", (int)line[0]);
10078 if (cpl_table_has_valid(dummy, name)) {
10079 rms = cpl_table_get_column_stdev(dummy, name);
10080 rms /= sqrt(ny - cpl_table_count_invalid(dummy, name));
10081 }
10082 else {
10083 rms = 0.0;
10084 }
10085 }
10086 else {
10087 rms = 0.0;
10088 }
10089
10090 rms /= sqrt(npoints);
10091
10092 cpl_vector_delete(offs);
10093
10094
10095
10096
10097
10098
10099 data = cpl_table_get_data_double(idscoeff, clab[0]);
10100 data[i] += offset;
10101
10102 data = cpl_table_get_data_double(idscoeff, "error");
10103 data[i] = sqrt(data[i]*data[i] + rms*rms);
10104
10105 idata = cpl_table_get_data_int(idscoeff, "nlines");
10106 idata[i] = npoints;
10107
10108
10109
10110
10111
10112
10113
10114 if (calibration) {
10115 for (k = 1; k < nx; k++) {
10116 lambda1 = cdata[k - 1 + i*nx];
10117 lambda2 = cdata[k + i*nx];
10118 if (lambda1 < 1.0 || lambda2 < 1.0)
10119 continue;
10120 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10121 }
10122 }
10123 }
10124 }
10125
10126 missing = 1;
10127 for (j = 0; j < nlines; j++) {
10128 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
10129 if (cpl_table_has_valid(dummy, name)) {
10130 missing = 0;
10131 offset = cpl_table_get_column_median(dummy, name);
10132 cpl_msg_info(func, "Median offset for %.3f: %.3f pixel",
10133 line[j], offset);
10134 }
10135 else {
10136 cpl_msg_info(func,
10137 "Median offset for %.2f: not available", line[j]);
10138 }
10139 }
10140
10141 cpl_table_delete(offsets);
10142
10143 if (missing) {
10144 cpl_table_delete(dummy);
10145 dummy = NULL;
10146 }
10147
10148 return dummy;
10149
10150 }
10151
10152
10180 double mos_distortions_rms(cpl_image *rectified, cpl_vector *lines,
10181 double wavestart, double dispersion, int radius,
10182 int highres)
10183 {
10184
10185 const char *func = "mos_distortions_rms";
10186
10187 int xlen;
10188 int ylen;
10189 int numLines;
10190 int cpix, npix, nzero;
10191 int sp, ep;
10192 int i, j, k;
10193 int npeaks, allPeaks;
10194
10195 float *profile;
10196 float peak, expectPeak, offset;
10197 double lambda;
10198
10199 double average;
10200 double rms, oneRms;
10201
10202 float *sdata;
10203 double *wdata;
10204
10205
10206 xlen = cpl_image_get_size_x(rectified);
10207 ylen = cpl_image_get_size_y(rectified);
10208 sdata = cpl_image_get_data(rectified);
10209
10210 if (lines) {
10211 wdata = cpl_vector_get_data(lines);
10212 numLines = cpl_vector_get_size(lines);
10213 }
10214 else {
10215 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
10216 "given: using internal list of reference sky lines");
10217 if (highres) {
10218 wdata = default_lines_hi;
10219 numLines = sizeof(default_lines_hi) / sizeof(double);
10220 }
10221 else {
10222 wdata = default_lines_lo;
10223 numLines = sizeof(default_lines_lo) / sizeof(double);
10224 }
10225 }
10226
10227 npix = 2 * radius + 1;
10228 profile = cpl_calloc(npix, sizeof(float));
10229
10230 rms = 0.0;
10231 allPeaks = 0;
10232
10233 for (i = 0; i < numLines; i++) {
10234
10235
10236
10237
10238
10239 lambda = wdata[i];
10240 expectPeak = (lambda - wavestart) / dispersion;
10241 cpix = floor(expectPeak + 0.5);
10242
10243
10244
10245
10246
10247 sp = cpix - radius;
10248 ep = cpix + radius;
10249
10250 if (sp < 0 || ep > xlen)
10251 continue;
10252
10253 average = 0.0;
10254 npeaks = 0;
10255 oneRms = 0.0;
10256
10257 for (j = 0; j < ylen; j++) {
10258 nzero = 0;
10259 for (k = 0; k < npix; k++) {
10260 profile[k] = sdata[sp + k + j * xlen];
10261 if (fabs(profile[k]) < 0.0001)
10262 nzero++;
10263 }
10264 if (nzero > 0)
10265 continue;
10266
10267 if (peakPosition(profile, npix, &peak, 1) == 0) {
10268 offset = (sp + peak) - expectPeak;
10269 average += offset;
10270 rms += fabs(offset);
10271 oneRms += fabs(offset);
10272 npeaks++;
10273 allPeaks++;
10274 }
10275 }
10276
10277 if (npeaks)
10278 cpl_msg_info(func, "RMS for %.2f: %.3f pixel (%d points)",
10279 lambda, oneRms / npeaks * 1.25, npeaks);
10280 else
10281 cpl_msg_info(func, "RMS for %.2f: line not available", lambda);
10282 }
10283
10284 cpl_free(profile);
10285
10286 if (allPeaks < 10)
10287 return 0.0;
10288
10289 rms /= allPeaks;
10290 rms *= 1.25;
10291
10292 return rms;
10293
10294 }
10295
10296
10317 cpl_image *mos_map_pixel(cpl_table *idscoeff, double reference,
10318 double blue, double red, double dispersion, int trend)
10319 {
10320 const char *func = "mos_map_pixel";
10321
10322 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10323
10324
10325 cpl_polynomial *ids;
10326 cpl_image *map;
10327 float *mdata;
10328 double lambda;
10329 double c;
10330 int order;
10331 int xsize, ysize;
10332 int missing;
10333 int i, j, k;
10334
10335
10336 if (idscoeff == NULL) {
10337 cpl_msg_error(func, "An IDS coeff table must be given");
10338 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10339 return NULL;
10340 }
10341
10342 xsize = (red - blue) / dispersion;
10343 ysize = cpl_table_get_nrow(idscoeff);
10344 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
10345 mdata = cpl_image_get_data(map);
10346
10347 order = 0;
10348 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
10349 ++order;
10350 --order;
10351
10352 for (i = 0; i < ysize; i++, mdata += xsize) {
10353
10354 missing = 0;
10355 ids = cpl_polynomial_new(1);
10356 for (k = trend; k <= order; k++) {
10357 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
10358 if (missing) {
10359 cpl_polynomial_delete(ids);
10360 break;
10361 }
10362 cpl_polynomial_set_coeff(ids, &k, c);
10363 }
10364 if (missing)
10365 continue;
10366
10367 for (j = 0; j < xsize; j++) {
10368 lambda = blue + j*dispersion;
10369 mdata[j] = cpl_polynomial_eval_1d(ids, lambda-reference, NULL);
10370 }
10371
10372 cpl_polynomial_delete(ids);
10373 }
10374
10375 return map;
10376
10377 }
10378
10379
10401 cpl_image *mos_map_idscoeff(cpl_table *idscoeff, int xsize, double reference,
10402 double blue, double red)
10403 {
10404 const char *func = "mos_map_idscoeff";
10405
10406 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10407
10408
10409 cpl_polynomial *ids;
10410 cpl_image *map;
10411 float *mdata;
10412 double lambda;
10413 double c;
10414 int order;
10415 int ysize;
10416 int missing;
10417 int i, j, k;
10418
10419
10420 if (idscoeff == NULL) {
10421 cpl_msg_error(func, "An IDS coeff table must be given");
10422 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10423 return NULL;
10424 }
10425
10426 if (xsize < 1) {
10427 cpl_msg_error(func, "Invalid image size");
10428 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10429 return NULL;
10430 }
10431
10432 if (xsize < 20 || xsize > 5000) {
10433 cpl_msg_warning(func, "Do you really have a detector %d pixels long?",
10434 xsize);
10435 }
10436
10437 ysize = cpl_table_get_nrow(idscoeff);
10438 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
10439 mdata = cpl_image_get_data(map);
10440
10441 order = 0;
10442 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
10443 ++order;
10444 --order;
10445
10446 for (i = 0; i < ysize; i++, mdata += xsize) {
10447
10448 missing = 0;
10449 ids = cpl_polynomial_new(1);
10450 for (k = 0; k <= order; k++) {
10451 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
10452 if (missing) {
10453 cpl_polynomial_delete(ids);
10454 break;
10455 }
10456 cpl_polynomial_set_coeff(ids, &k, c);
10457 }
10458 if (missing)
10459 continue;
10460
10461 for (j = 0; j < xsize; j++) {
10462 lambda = mos_eval_dds(ids, blue, red, reference, j);
10463 if (lambda >= blue && lambda <= red) {
10464 mdata[j] = lambda;
10465 }
10466 }
10467
10468 cpl_polynomial_delete(ids);
10469 }
10470
10471 return map;
10472
10473 }
10474
10475
10510 cpl_image *mos_map_wavelengths(cpl_image *spatial, cpl_image *calibration,
10511 cpl_table *slits, cpl_table *polytraces,
10512 double reference, double blue, double red,
10513 double dispersion)
10514 {
10515 const char *func = "mos_map_wavelengths";
10516
10517 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10518
10519 cpl_polynomial *polytop;
10520 cpl_polynomial *polybot;
10521 cpl_image *remapped;
10522 float *data;
10523 float *wdata;
10524 float *sdata;
10525 float *xdata;
10526 double vtop, vbot, value;
10527 double top, bot;
10528 double coeff;
10529 double ytop, ybot;
10530 double ypos;
10531 double fvalue;
10532 int ivalue;
10533 int yint, ysize, yprev;
10534 int nslits;
10535 int npseudo;
10536 int *slit_id;
10537 int *position;
10538 int *length;
10539 int nx, ny;
10540 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
10541 int missing_top, missing_bot;
10542 int null;
10543 int order;
10544 int i, j, k;
10545
10546
10547 if (spatial == NULL || calibration == NULL ||
10548 slits == NULL || polytraces == NULL) {
10549 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10550 return NULL;
10551 }
10552
10553 if (dispersion <= 0.0) {
10554 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10555 return NULL;
10556 }
10557
10558 if (red - blue < dispersion) {
10559 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10560 return NULL;
10561 }
10562
10563 nx = cpl_image_get_size_x(spatial);
10564 ny = cpl_image_get_size_y(spatial);
10565 ysize = cpl_image_get_size_y(calibration);
10566 remapped = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
10567 data = cpl_image_get_data(remapped);
10568 sdata = cpl_image_get_data(spatial);
10569 wdata = cpl_image_get_data(calibration);
10570
10571 nslits = cpl_table_get_nrow(slits);
10572 slit_id = cpl_table_get_data_int(slits, "slit_id");
10573 order = cpl_table_get_ncol(polytraces) - 2;
10574 position = cpl_table_get_data_int(slits, "position");
10575 length = cpl_table_get_data_int(slits, "length");
10576
10577
10578
10579
10580
10581
10582 pixel_above = (red - reference) / dispersion;
10583 pixel_below = (reference - blue) / dispersion;
10584
10585 for (i = 0; i < nslits; i++) {
10586
10587 if (length[i] == 0)
10588 continue;
10589
10590
10591
10592
10593
10594
10595
10596
10597
10598
10599
10600
10601 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
10602
10603 start_pixel = refpixel - pixel_below;
10604 if (start_pixel < 0)
10605 start_pixel = 0;
10606
10607 end_pixel = refpixel + pixel_above;
10608 if (end_pixel > nx)
10609 end_pixel = nx;
10610
10611
10612
10613
10614
10615
10616 missing_top = 0;
10617 polytop = cpl_polynomial_new(1);
10618 for (k = 0; k <= order; k++) {
10619 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
10620 if (null) {
10621 cpl_polynomial_delete(polytop);
10622 missing_top = 1;
10623 break;
10624 }
10625 cpl_polynomial_set_coeff(polytop, &k, coeff);
10626 }
10627
10628 missing_bot = 0;
10629 polybot = cpl_polynomial_new(1);
10630 for (k = 0; k <= order; k++) {
10631 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
10632 if (null) {
10633 cpl_polynomial_delete(polybot);
10634 missing_bot = 1;
10635 break;
10636 }
10637 cpl_polynomial_set_coeff(polybot, &k, coeff);
10638 }
10639
10640 if (missing_top && missing_bot) {
10641 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
10642 slit_id[i]);
10643 continue;
10644 }
10645
10646
10647
10648
10649
10650
10651
10652 if (missing_top) {
10653 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
10654 "the spectral curvature of the lower edge "
10655 "is used instead.", slit_id[i]);
10656 polytop = cpl_polynomial_duplicate(polybot);
10657 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
10658 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
10659 k = 0;
10660 coeff = cpl_polynomial_get_coeff(polybot, &k);
10661 coeff += ytop - ybot;
10662 cpl_polynomial_set_coeff(polytop, &k, coeff);
10663 }
10664
10665 if (missing_bot) {
10666 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
10667 "the spectral curvature of the upper edge "
10668 "is used instead.", slit_id[i]);
10669 polybot = cpl_polynomial_duplicate(polytop);
10670 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
10671 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
10672 k = 0;
10673 coeff = cpl_polynomial_get_coeff(polytop, &k);
10674 coeff -= ytop - ybot;
10675 cpl_polynomial_set_coeff(polybot, &k, coeff);
10676 }
10677
10678
10679
10680
10681
10682
10683
10684
10685 xdata = wdata + nx*position[i];
10686 npseudo = length[i] - 1;
10687
10688
10689
10690
10691
10692 for (j = start_pixel; j < end_pixel; j++) {
10693 top = cpl_polynomial_eval_1d(polytop, j, NULL);
10694 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
10695 for (k = 0; k <= npseudo; k++) {
10696 ypos = top - k*(top-bot)/npseudo;
10697 yint = ypos;
10698
10699
10700
10701
10702
10703
10704
10705
10706 if (yint < 0 || yint >= ny-1) {
10707 yprev = yint;
10708 continue;
10709 }
10710
10711 value = sdata[j + nx*yint];
10712 ivalue = value;
10713 fvalue = value - ivalue;
10714 if (ivalue < npseudo && ivalue >= 0) {
10715 vtop = xdata[j + nx*(npseudo-ivalue)];
10716 vbot = xdata[j + nx*(npseudo-ivalue-1)];
10717 if (vtop < 1.0) {
10718 if (vbot < 1.0) {
10719 value = 0.0;
10720 }
10721 else {
10722 value = vbot;
10723 }
10724 }
10725 else if (vbot < 1.0) {
10726 if (k)
10727 value = vtop;
10728 else
10729 value = 0.0;
10730 }
10731 else if (fabs(vbot-vtop) > 10*dispersion) {
10732 value = 0.0;
10733 }
10734 else {
10735 value = vtop*(1-fvalue) + vbot*fvalue;
10736 }
10737 data[j + nx*yint] = value;
10738
10739 if (k) {
10740
10741
10742
10743
10744
10745
10746
10747 if (yprev - yint > 1) {
10748 value = sdata[j + nx*(yint+1)];
10749 ivalue = value;
10750 fvalue = value - ivalue;
10751 if (ivalue < npseudo && ivalue >= 0) {
10752 vtop = xdata[j + nx*(npseudo-ivalue)];
10753 vbot = xdata[j + nx*(npseudo-ivalue-1)];
10754 if (vtop < 1.0) {
10755 if (vbot < 1.0) {
10756 value = data[j + nx*(yint+1)];
10757 }
10758 else {
10759 value = vbot;
10760 }
10761 }
10762 else if (vbot < 1.0) {
10763 value = vtop;
10764 }
10765 else if (fabs(vbot-vtop) > 2*dispersion) {
10766 value = vtop;
10767 }
10768 else {
10769 value = vtop*(1-fvalue) + vbot*fvalue;
10770 }
10771 data[j + nx*(yint+1)] = value;
10772 }
10773 }
10774 }
10775 }
10776 yprev = yint;
10777 }
10778 }
10779 cpl_polynomial_delete(polytop);
10780 cpl_polynomial_delete(polybot);
10781 }
10782
10783 return remapped;
10784 }
10785
10859 cpl_image *mos_map_spectrum(cpl_image *spectra, cpl_image *wavecalib,
10860 cpl_image *spatial, cpl_table *slits,
10861 cpl_table *polytraces, double reference,
10862 double blue, double red, double dispersion,
10863 int flux)
10864 {
10865 const char *func = "mos_map_spectrum";
10866
10867 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10868
10869 cpl_polynomial *polytop;
10870 cpl_polynomial *polybot;
10871 cpl_image *remapped;
10872 cpl_image **exslit;
10873 float *data;
10874 float *wdata;
10875 float *sdata;
10876 float *xdata;
10877 double lambda00, lambda01, lambda10, lambda11, lambda;
10878 double space00, space01, space10, space11, space;
10879 double value00, value01, value10, value11, value0, value1, value;
10880 double dL, dS;
10881 double top, bot;
10882 double coeff;
10883 double ytop, ybot;
10884 double xfrac, yfrac;
10885 int yint, ysize;
10886 int itop, ibot;
10887 int shift;
10888 int L, S;
10889 int nslits;
10890 int npseudo;
10891 int *slit_id;
10892 int *position;
10893 int *length;
10894 int nx, ny;
10895 int x, y;
10896 int nlambda;
10897 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
10898 int missing_top, missing_bot;
10899 int null;
10900 int order;
10901 int i, k;
10902
10903
10904 flux += flux;
10905
10906 if (spectra == NULL || spatial == NULL || wavecalib == NULL ||
10907 slits == NULL || polytraces == NULL) {
10908 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10909 return NULL;
10910 }
10911
10912 if (dispersion <= 0.0) {
10913 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10914 return NULL;
10915 }
10916
10917 if (red - blue < dispersion) {
10918 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10919 return NULL;
10920 }
10921
10922 nx = cpl_image_get_size_x(spectra);
10923 ny = cpl_image_get_size_y(spectra);
10924
10925 if (nx != cpl_image_get_size_x(spatial) ||
10926 ny != cpl_image_get_size_y(spatial) ||
10927 nx != cpl_image_get_size_x(wavecalib) ||
10928 ny != cpl_image_get_size_y(wavecalib)) {
10929 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
10930 return NULL;
10931 }
10932
10933 nlambda = (red - blue) / dispersion;
10934 pixel_above = (red - reference) / dispersion;
10935 pixel_below = (reference - blue) / dispersion;
10936
10937 data = cpl_image_get_data(spectra);
10938 sdata = cpl_image_get_data(spatial);
10939 wdata = cpl_image_get_data(wavecalib);
10940
10941 nslits = cpl_table_get_nrow(slits);
10942 slit_id = cpl_table_get_data_int(slits, "slit_id");
10943 order = cpl_table_get_ncol(polytraces) - 2;
10944 position = cpl_table_get_data_int(slits, "position");
10945 length = cpl_table_get_data_int(slits, "length");
10946
10947 exslit = cpl_calloc(nslits, sizeof(cpl_image *));
10948
10949 for (i = 0; i < nslits; i++) {
10950
10951 if (length == 0)
10952 continue;
10953
10954
10955
10956
10957
10958
10959
10960
10961
10962
10963
10964
10965 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
10966
10967 start_pixel = refpixel - pixel_below;
10968 if (start_pixel < 1)
10969 start_pixel = 1;
10970
10971 end_pixel = refpixel + pixel_above;
10972 if (end_pixel > nx)
10973 end_pixel = nx;
10974
10975
10976
10977
10978
10979
10980 missing_top = 0;
10981 polytop = cpl_polynomial_new(1);
10982 for (k = 0; k <= order; k++) {
10983 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
10984 if (null) {
10985 cpl_polynomial_delete(polytop);
10986 missing_top = 1;
10987 break;
10988 }
10989 cpl_polynomial_set_coeff(polytop, &k, coeff);
10990 }
10991
10992 missing_bot = 0;
10993 polybot = cpl_polynomial_new(1);
10994 for (k = 0; k <= order; k++) {
10995 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
10996 if (null) {
10997 cpl_polynomial_delete(polybot);
10998 missing_bot = 1;
10999 break;
11000 }
11001 cpl_polynomial_set_coeff(polybot, &k, coeff);
11002 }
11003
11004 if (missing_top && missing_bot) {
11005 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
11006 slit_id[i]);
11007 continue;
11008 }
11009
11010
11011
11012
11013
11014
11015
11016 if (missing_top) {
11017 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
11018 "the spectral curvature of the lower edge "
11019 "is used instead.", slit_id[i]);
11020 polytop = cpl_polynomial_duplicate(polybot);
11021 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
11022 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
11023 k = 0;
11024 coeff = cpl_polynomial_get_coeff(polybot, &k);
11025 coeff += ytop - ybot;
11026 cpl_polynomial_set_coeff(polytop, &k, coeff);
11027 }
11028
11029 if (missing_bot) {
11030 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
11031 "the spectral curvature of the upper edge "
11032 "is used instead.", slit_id[i]);
11033 polybot = cpl_polynomial_duplicate(polytop);
11034 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
11035 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
11036 k = 0;
11037 coeff = cpl_polynomial_get_coeff(polytop, &k);
11038 coeff -= ytop - ybot;
11039 cpl_polynomial_set_coeff(polybot, &k, coeff);
11040 }
11041
11042
11043
11044
11045
11046 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
11047 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
11048 npseudo = ceil(top-bot) + 1;
11049
11050 if (npseudo < 1) {
11051 cpl_polynomial_delete(polytop);
11052 cpl_polynomial_delete(polybot);
11053 cpl_msg_debug(func, "Slit %d was badly traced: no extraction!",
11054 slit_id[i]);
11055 continue;
11056 }
11057
11058 exslit[i] = cpl_image_new(nlambda, npseudo+1, CPL_TYPE_FLOAT);
11059 xdata = cpl_image_get_data(exslit[i]);
11060
11061
11062
11063
11064
11065 for (x = start_pixel; x < end_pixel; x++) {
11066 top = cpl_polynomial_eval_1d(polytop, x, NULL);
11067 bot = cpl_polynomial_eval_1d(polybot, x, NULL);
11068 itop = top + 1;
11069 ibot = bot;
11070 if (itop < 0)
11071 itop = 0;
11072 if (itop > ny - 1)
11073 itop = ny - 1;
11074 if (ibot < 0)
11075 ibot = 0;
11076 if (ibot > ny - 1)
11077 ibot = ny - 1;
11078 for (y = ibot; y < itop; y++) {
11079 lambda11 = wdata[x + y*nx];
11080 if (lambda11 < 1.0)
11081 continue;
11082 space11 = sdata[x + y*nx];
11083 if (space11 < 0.0)
11084 continue;
11085 lambda01 = wdata[x - 1 + y*nx];
11086 if (lambda01 < 1.0)
11087 continue;
11088 space01 = sdata[x - 1 + y*nx];
11089 if (space01 < 0.0)
11090 continue;
11091
11092 shift = 0;
11093
11094
11095
11096
11097
11098
11099
11100
11101
11102
11103
11104
11105
11106
11107
11108
11109
11110
11111
11112
11113
11114
11115
11116
11117
11118
11119
11120
11121 lambda10 = wdata[x + shift + (y+1)*nx];
11122 if (lambda10 < 1.0)
11123 continue;
11124 space10 = sdata[x + shift + (y+1)*nx];
11125 if (space10 < 0.0)
11126 continue;
11127 lambda00 = wdata[x - 1 + shift + (y+1)*nx];
11128 if (lambda00 < 1.0)
11129 continue;
11130 space00 = sdata[x - 1 + shift + (y+1)*nx];
11131 if (space00 < 0.0)
11132 continue;
11133
11134
11135
11136
11137
11138
11139
11140 dL = lambda11 - lambda01;
11141 dS = space11 - space10;
11142
11143
11144
11145
11146
11147
11148 L = (lambda11 - blue)/dispersion + 0.5;
11149 S = space11 + 0.5;
11150
11151 if (L < 0 || L >= nlambda)
11152 continue;
11153 if (S < 0 || S > npseudo)
11154 continue;
11155
11156
11157
11158
11159
11160 lambda = blue + L*dispersion;
11161 space = S;
11162
11163
11164
11165
11166
11167
11168
11169
11170
11171
11172 xfrac = (lambda11-lambda)/dL;
11173 yfrac = (space11-space)/dS;
11174
11175
11176
11177
11178
11179
11180
11181
11182
11183
11184 value11 = data[x + y*nx];
11185 value01 = data[x - 1 + y*nx];
11186 value10 = data[x + shift + (y+1)*nx];
11187 value00 = data[x + shift - 1 + (y+1)*nx];
11188
11189
11190
11191
11192
11193 value1 = (1-xfrac)*value11 + xfrac*value01;
11194 value0 = (1-xfrac)*value10 + xfrac*value00;
11195 value = (1-yfrac)*value1 + yfrac*value0;
11196
11197
11198
11199
11200
11201
11202 xdata[L + nlambda*(npseudo-S)] = value;
11203
11204 }
11205 }
11206 cpl_polynomial_delete(polytop);
11207 cpl_polynomial_delete(polybot);
11208 }
11209
11210
11211
11212
11213
11214 ysize = 0;
11215 for (i = 0; i < nslits; i++)
11216 if (exslit[i])
11217 ysize += cpl_image_get_size_y(exslit[i]);
11218
11219 remapped = cpl_image_new(nlambda, ysize, CPL_TYPE_FLOAT);
11220
11221 yint = -1;
11222 for (i = 0; i < nslits; i++) {
11223 if (exslit[i]) {
11224 yint += cpl_image_get_size_y(exslit[i]);
11225 cpl_image_copy(remapped, exslit[i], 1, ysize - yint);
11226 cpl_image_delete(exslit[i]);
11227 cpl_table_set_int(slits, "position", i, ysize - yint - 1);
11228 }
11229 }
11230
11231 cpl_free(exslit);
11232
11233 return remapped;
11234
11235 }
11236
11237
11270 cpl_table *mos_sky_map_super(cpl_image *spectra, cpl_image *wavemap,
11271 double dispersion, double factor, int minpoints,
11272 cpl_image *skymap)
11273 {
11274 const char *func = "mos_sky_map_super";
11275
11276 cpl_vector **vector;
11277 cpl_vector **wvector;
11278 double firstLambda, lastLambda;
11279 double lambda, lambda1, lambda2;
11280 double value, value1, value2;
11281 double frac;
11282 float min, max;
11283 int *count;
11284 int nbin, bin;
11285 int nx, ny, npix;
11286 int first_valid, valid_bins;
11287 int i, j;
11288
11289 cpl_table *sky;
11290 double *sky_spectrum;
11291 double *sky_wave;
11292 float *data;
11293 float *sdata;
11294 float *kdata;
11295
11296
11297 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
11298 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11299 return NULL;
11300 }
11301
11302 if (dispersion <= 0.0) {
11303 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11304 cpl_msg_error(func, "Negative dispersion: %s", cpl_error_get_message());
11305 return NULL;
11306 }
11307
11308 nx = cpl_image_get_size_x(spectra);
11309 ny = cpl_image_get_size_y(spectra);
11310 npix = nx * ny;
11311
11312 if (nx != cpl_image_get_size_x(wavemap) ||
11313 ny != cpl_image_get_size_y(wavemap) ||
11314 nx != cpl_image_get_size_x(skymap) ||
11315 ny != cpl_image_get_size_y(skymap)) {
11316 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
11317 cpl_msg_error(func, "Image sizes: %s", cpl_error_get_message());
11318 return NULL;
11319 }
11320
11321 if (factor < 1.0) {
11322 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11323 cpl_msg_error(func, "Undersampling (%f): %s", factor,
11324 cpl_error_get_message());
11325 return NULL;
11326 }
11327
11328 if (minpoints < 0) {
11329 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11330 cpl_msg_error(func, "Negative threshold: %s", cpl_error_get_message());
11331 return NULL;
11332 }
11333
11334 dispersion /= factor;
11335
11336
11337
11338
11339
11340
11341 data = cpl_image_get_data(wavemap);
11342
11343 for (i = 0; i < npix; i++) {
11344 if (data[i] > 1.0) {
11345 min = max = data[i];
11346 j = i+1;
11347 break;
11348 }
11349 }
11350
11351 for (i = j; i < npix; i++) {
11352 if (data[i] < 1.0)
11353 continue;
11354 if (min > data[i])
11355 min = data[i];
11356 if (max < data[i])
11357 max = data[i];
11358 }
11359
11360 firstLambda = min;
11361 lastLambda = max;
11362
11363
11364
11365
11366
11367
11368 nbin = (lastLambda - firstLambda) / dispersion;
11369
11370
11371
11372
11373
11374
11375
11376
11377 count = cpl_calloc(nbin, sizeof(int));
11378
11379 data = cpl_image_get_data(wavemap);
11380
11381 for (i = 0; i < npix; i++) {
11382 if (data[i] < 1.0)
11383 continue;
11384 bin = (data[i] - firstLambda) / dispersion;
11385 if (bin < nbin)
11386 count[bin]++;
11387 }
11388
11389 valid_bins = 0;
11390 for (i = 0; i < nbin; i++)
11391 if (count[i] >= minpoints)
11392 valid_bins++;
11393
11394 if (valid_bins < nbin/3) {
11395 cpl_msg_warning(func, "Cannot determine a good global sky "
11396 "spectrum from input data");
11397 return NULL;
11398 }
11399
11400
11401
11402
11403
11404
11405
11406
11407
11408 vector = cpl_calloc(nbin, sizeof(cpl_vector *));
11409 wvector = cpl_calloc(nbin, sizeof(cpl_vector *));
11410 for (i = 0; i < nbin; i++) {
11411 if (count[i] >= minpoints) {
11412 vector[i] = cpl_vector_new(count[i]);
11413 wvector[i] = cpl_vector_new(count[i]);
11414 }
11415 count[i] = 0;
11416 }
11417
11418
11419
11420
11421
11422
11423
11424 data = cpl_image_get_data(wavemap);
11425 sdata = cpl_image_get_data(spectra);
11426
11427 for (i = 0; i < npix; i++) {
11428 if (data[i] < 1.0)
11429 continue;
11430 bin = (data[i] - firstLambda) / dispersion;
11431 if (bin < nbin) {
11432 if (vector[bin]) {
11433 cpl_vector_set(vector[bin], count[bin], sdata[i]);
11434 cpl_vector_set(wvector[bin], count[bin], data[i]);
11435 }
11436 count[bin]++;
11437 }
11438 }
11439
11440
11441
11442
11443
11444
11445
11446 sky_spectrum = cpl_calloc(nbin, sizeof(double));
11447 sky_wave = cpl_calloc(nbin, sizeof(double));
11448 for (i = 0; i < nbin; i++) {
11449 if (vector[i]) {
11450 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
11451 sky_wave[i] = cpl_vector_get_median_const(wvector[i]);
11452 cpl_vector_delete(vector[i]);
11453 cpl_vector_delete(wvector[i]);
11454 }
11455 }
11456
11457 cpl_free(vector);
11458 cpl_free(wvector);
11459
11460
11461
11462
11463
11464
11465 for (i = 0; i < nbin; i++) {
11466 if (count[i] >= minpoints) {
11467 first_valid = i;
11468 break;
11469 }
11470 }
11471
11472 for (i = first_valid; i < nbin; i++) {
11473 if (count[i] < minpoints) {
11474 sky_wave[i] = firstLambda + (i+0.5)*dispersion;
11475 for (j = i+1; j < nbin; j++) {
11476 if (count[j] >= minpoints) {
11477 if (sky_wave[j] - sky_wave[i-1] < 0.1) {
11478 sky_spectrum[i] = (sky_spectrum[j] + sky_spectrum[i-1])
11479 / 2;
11480 }
11481 else {
11482 frac = (sky_wave[i] - sky_wave[i-1])
11483 / (sky_wave[j] - sky_wave[i-1]);
11484 sky_spectrum[i] = frac * sky_spectrum[j]
11485 + (1 - frac) * sky_spectrum[i-1];
11486 }
11487 }
11488 }
11489 }
11490 }
11491
11492
11493
11494
11495
11496
11497 sky = cpl_table_new(nbin);
11498 cpl_table_wrap_double(sky, sky_wave, "wavelength");
11499 cpl_table_wrap_double(sky, sky_spectrum, "sky");
11500 cpl_table_wrap_int(sky, count, "npoints");
11501
11502
11503
11504
11505
11506
11507 data = cpl_image_get_data(wavemap);
11508 sdata = cpl_image_get_data(spectra);
11509 kdata = cpl_image_get_data(skymap);
11510
11511 for (i = 0; i < npix; i++) {
11512
11513
11514
11515
11516
11517 lambda = data[i];
11518 if (lambda < 1.0)
11519 continue;
11520 bin = (lambda - firstLambda) / dispersion;
11521 lambda1 = sky_wave[bin];
11522 value1 = sky_spectrum[bin];
11523 if (lambda1 < lambda) {
11524 bin++;
11525 if (bin < nbin) {
11526 lambda2 = sky_wave[bin];
11527 value2 = sky_spectrum[bin];
11528 if (lambda2 - lambda1 < 0.1) {
11529 value = (value1 + value2) / 2;
11530 }
11531 else {
11532 frac = (lambda - lambda1) / (lambda2 - lambda1);
11533 value = frac * value2 + (1 - frac) * value1;
11534 }
11535 }
11536 else {
11537 value = value1;
11538 }
11539 }
11540 else {
11541 if (bin > 0) {
11542 bin--;
11543 lambda2 = lambda1;
11544 value2 = value1;
11545 lambda1 = sky_wave[bin];
11546 value1 = sky_spectrum[bin];
11547 if (lambda2 - lambda1 < 0.1) {
11548 value = (value1 + value2) / 2;
11549 }
11550 else {
11551 frac = (lambda - lambda1) / (lambda2 - lambda1);
11552 value = frac * value2 + (1 - frac) * value1;
11553 }
11554 }
11555 else {
11556 value = value1;
11557 }
11558 }
11559 kdata[i] = value;
11560 }
11561
11562 if (first_valid)
11563 cpl_table_erase_window(sky, 0, first_valid);
11564
11565 return sky;
11566
11567 }
11568
11569
11603 cpl_table *mos_sky_map(cpl_image *spectra, cpl_image *wavemap,
11604 double dispersion, cpl_image *skymap)
11605 {
11606 const char *func = "mos_sky_map";
11607
11608 cpl_vector **vector;
11609 double firstLambda, lastLambda;
11610 double lambda, lambda1, lambda2;
11611 double value, value1, value2;
11612 float min, max;
11613 int *count;
11614 int nbin, bin;
11615 int nx, ny, npix;
11616 int i, j;
11617
11618 cpl_table *sky;
11619 double *sky_spectrum;
11620 float *data;
11621 float *sdata;
11622 float *kdata;
11623 double *wdata;
11624
11625
11626 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
11627 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11628 return NULL;
11629 }
11630
11631 if (dispersion <= 0.0) {
11632 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11633 return NULL;
11634 }
11635
11636 nx = cpl_image_get_size_x(spectra);
11637 ny = cpl_image_get_size_y(spectra);
11638 npix = nx * ny;
11639
11640 if (nx != cpl_image_get_size_x(wavemap) ||
11641 ny != cpl_image_get_size_y(wavemap) ||
11642 nx != cpl_image_get_size_x(skymap) ||
11643 ny != cpl_image_get_size_y(skymap)) {
11644 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
11645 return NULL;
11646 }
11647
11648
11649
11650
11651
11652
11653 data = cpl_image_get_data(wavemap);
11654
11655 for (i = 0; i < npix; i++) {
11656 if (data[i] > 1.0) {
11657 min = max = data[i];
11658 j = i+1;
11659 break;
11660 }
11661 }
11662
11663 for (i = j; i < npix; i++) {
11664 if (data[i] < 1.0)
11665 continue;
11666 if (min > data[i])
11667 min = data[i];
11668 if (max < data[i])
11669 max = data[i];
11670 }
11671
11672 firstLambda = min;
11673 lastLambda = max;
11674
11675
11676
11677
11678
11679
11680 nbin = (lastLambda - firstLambda) / dispersion;
11681
11682
11683
11684
11685
11686
11687
11688
11689 count = cpl_calloc(nbin, sizeof(int));
11690
11691 data = cpl_image_get_data(wavemap);
11692
11693 for (i = 0; i < npix; i++) {
11694 if (data[i] < 1.0)
11695 continue;
11696 bin = (data[i] - firstLambda) / dispersion;
11697 if (bin < nbin)
11698 count[bin]++;
11699 }
11700
11701
11702
11703
11704
11705
11706
11707
11708
11709 vector = cpl_calloc(nbin, sizeof(cpl_vector *));
11710 for (i = 0; i < nbin; i++) {
11711 if (count[i])
11712 vector[i] = cpl_vector_new(count[i]);
11713 else
11714 vector[i] = NULL;
11715 count[i] = 0;
11716 }
11717
11718
11719
11720
11721
11722
11723
11724 data = cpl_image_get_data(wavemap);
11725 sdata = cpl_image_get_data(spectra);
11726
11727 for (i = 0; i < npix; i++) {
11728 if (data[i] < 1.0)
11729 continue;
11730 bin = (data[i] - firstLambda) / dispersion;
11731 if (bin < nbin) {
11732 cpl_vector_set(vector[bin], count[bin], sdata[i]);
11733 count[bin]++;
11734 }
11735 }
11736
11737
11738
11739
11740
11741
11742
11743 sky_spectrum = cpl_calloc(nbin, sizeof(double));
11744 for (i = 0; i < nbin; i++) {
11745 if (vector[i]) {
11746 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
11747 cpl_vector_delete(vector[i]);
11748 }
11749 }
11750
11751 cpl_free(vector);
11752
11753
11754
11755
11756
11757
11758
11759
11760
11761
11762
11763
11764
11765 sky = cpl_table_new(nbin);
11766 cpl_table_new_column(sky, "wavelength", CPL_TYPE_DOUBLE);
11767 cpl_table_set_column_unit(sky, "wavelength", "pixel");
11768 cpl_table_wrap_double(sky, sky_spectrum, "sky");
11769 cpl_table_wrap_int(sky, count, "npoints");
11770 for (i = 0; i < nbin; i++)
11771 cpl_table_set_double(sky, "wavelength", i,
11772 firstLambda + (i+0.5)*dispersion);
11773
11774
11775
11776
11777
11778
11779 data = cpl_image_get_data(wavemap);
11780 sdata = cpl_image_get_data(spectra);
11781 kdata = cpl_image_get_data(skymap);
11782 wdata = cpl_table_get_data_double(sky, "wavelength");
11783
11784 for (i = 0; i < npix; i++) {
11785
11786
11787
11788
11789
11790 lambda = data[i];
11791 if (lambda < 1.0)
11792 continue;
11793 bin = (lambda - firstLambda) / dispersion;
11794 lambda1 = wdata[bin];
11795 value1 = sky_spectrum[bin];
11796 if (lambda1 < lambda) {
11797 bin++;
11798 if (bin < nbin) {
11799 lambda2 = wdata[bin];
11800 value2 = sky_spectrum[bin];
11801 value = ((lambda2 - lambda)*value1
11802 + (lambda - lambda1)*value2) / dispersion;
11803 }
11804 else {
11805 value = value1;
11806 }
11807 }
11808 else {
11809 if (bin > 0) {
11810 bin--;
11811 lambda2 = lambda1;
11812 value2 = value1;
11813 lambda1 = wdata[bin];
11814 value1 = sky_spectrum[bin];
11815 value = ((lambda2 - lambda)*value1
11816 + (lambda - lambda1)*value2)/dispersion;
11817 }
11818 else {
11819 value = value1;
11820 }
11821 }
11822 kdata[i] = value;
11823 }
11824
11825 return sky;
11826
11827 }
11828
11829
11845 cpl_image *mos_sky_local_old(cpl_image *spectra, cpl_table *slits)
11846 {
11847 const char *func = "mos_sky_local_old";
11848
11849 cpl_image *exslit;
11850 cpl_image *sky;
11851 cpl_image *skymap;
11852 float *data;
11853 float *sdata;
11854 int nx, ny;
11855 int xlow, ylow, xhig, yhig;
11856 int nslits;
11857 int *slit_id;
11858 int *position;
11859 int *length;
11860 int i, j, k;
11861
11862
11863 if (spectra == NULL) {
11864 cpl_msg_error(func,
11865 "A scientific rectified spectral image must be given");
11866 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11867 return NULL;
11868 }
11869
11870 if (slits == NULL) {
11871 cpl_msg_error(func, "A slits position table must be given");
11872 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11873 return NULL;
11874 }
11875
11876 nslits = cpl_table_get_nrow(slits);
11877 slit_id = cpl_table_get_data_int(slits, "slit_id");
11878 position = cpl_table_get_data_int(slits, "position");
11879 length = cpl_table_get_data_int(slits, "length");
11880
11881 nx = cpl_image_get_size_x(spectra);
11882 ny = cpl_image_get_size_y(spectra);
11883
11884 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
11885
11886 xlow = 1;
11887 xhig = nx;
11888 for (i = 0; i < nslits; i++) {
11889
11890 if (length[i] == 0)
11891 continue;
11892
11893
11894
11895
11896
11897
11898
11899
11900
11901
11902
11903 ylow = position[i] + 1;
11904 yhig = ylow + length[i] - 1;
11905
11906 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
11907 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
11908 cpl_image_delete(exslit);
11909
11910 data = cpl_image_get_data(skymap);
11911 data += nx * position[i];
11912
11913 for (j = 0; j < length[i]; j++) {
11914 sdata = cpl_image_get_data(sky);
11915 for (k = 0; k < nx; k++) {
11916 *data++ = *sdata++;
11917 }
11918 }
11919
11920 cpl_image_delete(sky);
11921 }
11922
11923 return skymap;
11924
11925 }
11926
11927
11947 cpl_image *mos_sky_local(cpl_image *spectra, cpl_table *slits, int order)
11948 {
11949 const char *func = "mos_sky_local";
11950
11951 char name[MAX_COLNAME];
11952
11953 cpl_polynomial *fit;
11954 cpl_vector *points;
11955 cpl_vector *values;
11956 cpl_vector *keep_points;
11957 cpl_vector *keep_values;
11958 cpl_image *exslit;
11959 cpl_image *sky;
11960 cpl_image *subtracted;
11961 cpl_image *profile;
11962 cpl_image *skymap;
11963 cpl_table *objects;
11964 float *data;
11965 float *sdata;
11966 float *xdata;
11967 double *vdata;
11968 double *pdata;
11969 double median;
11970 int nx, ny;
11971 int xlow, ylow, xhig, yhig;
11972 int nslits;
11973 int *slit_id;
11974 int *position;
11975 int *length;
11976 int *is_sky;
11977 int nsky, nbad;
11978 int maxobjects;
11979 int margin = 3;
11980 int radius = 6;
11981 int i, j, k;
11982
11983
11984 if (spectra == NULL) {
11985 cpl_msg_error(func,
11986 "A scientific rectified spectral image must be given");
11987 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11988 return NULL;
11989 }
11990
11991 if (slits == NULL) {
11992 cpl_msg_error(func, "A slits position table must be given");
11993 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11994 return NULL;
11995 }
11996
11997 if (order < 0) {
11998 cpl_msg_error(func, "Invalid fit order");
11999 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12000 return NULL;
12001 }
12002
12003 nslits = cpl_table_get_nrow(slits);
12004 slit_id = cpl_table_get_data_int(slits, "slit_id");
12005 position = cpl_table_get_data_int(slits, "position");
12006 length = cpl_table_get_data_int(slits, "length");
12007
12008 nx = cpl_image_get_size_x(spectra);
12009 ny = cpl_image_get_size_y(spectra);
12010
12011 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12012
12013 xlow = 1;
12014 xhig = nx;
12015 for (i = 0; i < nslits; i++) {
12016
12017 if (length[i] == 0)
12018 continue;
12019
12020
12021
12022
12023
12024
12025
12026
12027
12028
12029
12030 ylow = position[i] + 1;
12031 yhig = ylow + length[i] - 1;
12032
12033 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
12034 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
12035 cpl_image_delete(exslit);
12036
12037 data = cpl_image_get_data(skymap);
12038 data += nx * position[i];
12039
12040 for (j = 0; j < length[i]; j++) {
12041 sdata = cpl_image_get_data(sky);
12042 for (k = 0; k < nx; k++) {
12043 *data++ = *sdata++;
12044 }
12045 }
12046
12047 cpl_image_delete(sky);
12048 }
12049
12050
12051
12052
12053
12054
12055 subtracted = cpl_image_duplicate(spectra);
12056 cpl_image_subtract(subtracted, skymap);
12057 cpl_image_delete(skymap);
12058
12059
12060
12061
12062
12063
12064 objects = cpl_table_duplicate(slits);
12065 profile = mos_detect_objects(subtracted, objects, margin, radius, 0);
12066 cpl_image_delete(profile);
12067 cpl_image_delete(subtracted);
12068
12069
12070
12071
12072
12073
12074
12075 maxobjects = 1;
12076 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
12077 while (cpl_table_has_column(objects, name)) {
12078 maxobjects++;
12079 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
12080 }
12081
12082 is_sky = cpl_calloc(ny, sizeof(int));
12083
12084 for (i = 0; i < nslits; i++) {
12085
12086 if (length[i] == 0)
12087 continue;
12088
12089 ylow = position[i] + margin;
12090 yhig = position[i] + length[i] - margin;
12091
12092 for (j = ylow; j < yhig; j++)
12093 is_sky[j] = 1;
12094
12095 for (j = 1; j < maxobjects; j++) {
12096 snprintf(name, MAX_COLNAME, "object_%d", j);
12097 if (cpl_table_is_valid(objects, name, i)) {
12098 snprintf(name, MAX_COLNAME, "start_%d", j);
12099 ylow = cpl_table_get_int(objects, name, i, NULL);
12100 snprintf(name, MAX_COLNAME, "end_%d", j);
12101 yhig = cpl_table_get_int(objects, name, i, NULL);
12102 for (k = ylow; k <= yhig; k++)
12103 is_sky[k] = 0;
12104 }
12105 }
12106
12107
12108
12109
12110
12111
12112 ylow = position[i] + margin + 1;
12113 yhig = position[i] + length[i] - margin - 1;
12114
12115 for (j = ylow; j < yhig; j++)
12116 if (is_sky[j])
12117 if (is_sky[j-1] == 0 && is_sky[j+1] == 0)
12118 is_sky[j] = 0;
12119
12120 }
12121
12122
12123
12124
12125
12126
12127 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12128
12129 for (i = 0; i < nslits; i++) {
12130
12131 if (length[i] == 0)
12132 continue;
12133
12134 ylow = position[i];
12135 yhig = ylow + length[i];
12136
12137 nsky = 0;
12138 for (j = ylow; j < yhig; j++)
12139 if (is_sky[j])
12140 nsky++;
12141
12142 if (nsky > order + 1) {
12143 if (order) {
12144 points = cpl_vector_new(nsky);
12145 nsky = 0;
12146 for (j = ylow; j < yhig; j++) {
12147 if (is_sky[j]) {
12148 cpl_vector_set(points, nsky, j);
12149 nsky++;
12150 }
12151 }
12152
12153 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
12154 xdata = cpl_image_get_data(exslit);
12155 values = cpl_vector_new(nsky);
12156
12157 for (j = 0; j < nx; j++) {
12158 nsky = 0;
12159 for (k = ylow; k < yhig; k++) {
12160 if (is_sky[k]) {
12161 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
12162 nsky++;
12163 }
12164 }
12165
12166
12167
12168
12169
12170 median = cpl_vector_get_median_const(values);
12171 vdata = cpl_vector_get_data(values);
12172 pdata = cpl_vector_get_data(points);
12173 nbad = 0;
12174 for (k = 0; k < nsky; k++) {
12175 if (fabs(vdata[k] - median) < 100) {
12176 if (nbad) {
12177 vdata[k-nbad] = vdata[k];
12178 pdata[k-nbad] = pdata[k];
12179 }
12180 }
12181 else
12182 nbad++;
12183 }
12184
12185 if (nsky == nbad)
12186 continue;
12187
12188 if (nbad && nsky - nbad > order + 1) {
12189 keep_values = values;
12190 keep_points = points;
12191 values = cpl_vector_wrap(nsky-nbad, vdata);
12192 points = cpl_vector_wrap(nsky-nbad, pdata);
12193 }
12194
12195 if (nsky - nbad > order + 1) {
12196
12197 fit = cpl_polynomial_fit_1d_create(points, values,
12198 order, NULL);
12199
12200 if (fit) {
12201 for (k = ylow; k < yhig; k++) {
12202 xdata[j+(k-ylow)*nx] =
12203 cpl_polynomial_eval_1d(fit, k, NULL);
12204 }
12205
12206 cpl_polynomial_delete(fit);
12207 }
12208 else
12209 cpl_error_reset();
12210 }
12211 else {
12212 for (k = 0; k < nsky; k++) {
12213 xdata[j+k*nx] = median;
12214 }
12215 }
12216
12217 if (nbad && nsky - nbad > order + 1) {
12218 cpl_vector_unwrap(values);
12219 cpl_vector_unwrap(points);
12220 values = keep_values;
12221 points = keep_points;
12222 }
12223
12224 if (nbad) {
12225 nsky = 0;
12226 for (k = ylow; k < yhig; k++) {
12227 if (is_sky[k]) {
12228 cpl_vector_set(points, nsky, k);
12229 nsky++;
12230 }
12231 }
12232 }
12233
12234 }
12235
12236 cpl_vector_delete(values);
12237 cpl_vector_delete(points);
12238
12239 cpl_image_copy(skymap, exslit, 1, ylow+1);
12240 cpl_image_delete(exslit);
12241
12242 }
12243 else {
12244 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
12245 xdata = cpl_image_get_data(exslit);
12246 values = cpl_vector_new(nsky);
12247
12248 for (j = 0; j < nx; j++) {
12249 nsky = 0;
12250 for (k = ylow; k < yhig; k++) {
12251 if (is_sky[k]) {
12252 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
12253 nsky++;
12254 }
12255 }
12256
12257 median = cpl_vector_get_median_const(values);
12258
12259 for (k = ylow; k < yhig; k++)
12260 xdata[j+(k-ylow)*nx] = median;
12261
12262 }
12263
12264 cpl_vector_delete(values);
12265
12266 cpl_image_copy(skymap, exslit, 1, ylow+1);
12267 cpl_image_delete(exslit);
12268 }
12269 }
12270 else
12271 cpl_msg_warning(func, "Too few sky points in slit %d", i + 1);
12272 }
12273
12274 cpl_free(is_sky);
12275
12276 return skymap;
12277
12278 }
12279
12280
12302 cpl_error_code mos_clean_cosmics(cpl_image *image, float gain,
12303 float threshold, float ratio)
12304 {
12305 const char *func = "mos_clean_cosmics";
12306
12307 cpl_image *smoothImage;
12308 cpl_table *table;
12309 cpl_matrix *kernel;
12310 int *xdata;
12311 int *ydata;
12312 float *idata;
12313 float *sdata;
12314 float sigma, sum, value, smoothValue;
12315 double noise;
12316 int count;
12317 float fMax;
12318 int iMin, iMax, jMin, jMax, iPosMax, jPosMax;
12319 int xLen;
12320 int yLen;
12321 int nPix;
12322 int first = 1;
12323
12324 int pos, i, j, k, l, ii, jj, iii = 0, jjj = 0;
12325 int numCosmic = 0;
12326 int found, foundContiguousCandidate;
12327 int *cosmic;
12328
12329
12330 if (image == NULL)
12331 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12332
12333
12334
12335
12336
12337
12338
12339
12340
12341
12342
12343
12344 xLen = cpl_image_get_size_x(image);
12345 yLen = cpl_image_get_size_y(image);
12346
12347 if (xLen < 4 || yLen < 4)
12348 return CPL_ERROR_NONE;
12349
12350 nPix = xLen * yLen;
12351
12352
12353
12354
12355
12356
12357
12358
12359
12360
12361
12362
12363
12364
12365
12366
12367
12368
12369
12370
12371
12372
12373 idata = cpl_image_get_data(image);
12374 noise = 0.0;
12375 count = 0;
12376
12377 for (i = 0; i < nPix; i++) {
12378 if (idata[i] < -0.00001) {
12379 noise -= idata[i];
12380 count++;
12381 }
12382 }
12383
12384 noise /= count;
12385 noise *= 1.25;
12386
12387 cosmic = cpl_calloc(nPix, sizeof(int));
12388
12389 if (threshold < 0.)
12390 threshold = 4.0;
12391 if (ratio < 0.)
12392 ratio = 2.0;
12393
12394 kernel = cpl_matrix_new(3, 3);
12395 cpl_matrix_fill(kernel, 1.0);
12396 cpl_matrix_set(kernel, 1, 1, 0.0);
12397 smoothImage = cpl_image_filter_median(image, kernel);
12398 cpl_matrix_delete(kernel);
12399
12400
12401
12402
12403
12404
12405
12406
12407
12408
12409 sdata = cpl_image_get_data(smoothImage);
12410
12411 for (j = 1; j < yLen - 1; j++) {
12412 for (i = 1; i < xLen - 1; i++) {
12413 value = idata[i + j * xLen];
12414 smoothValue = sdata[i + j * xLen];
12415 if (smoothValue < 1.0)
12416 smoothValue = 1.0;
12417 sigma = sqrt(noise * noise + smoothValue / gain);
12418 if (value - smoothValue >= threshold * sigma)
12419 cosmic[i + j * xLen] = -1;
12420 }
12421 }
12422
12423 cpl_image_delete(smoothImage);
12424
12425
12426
12427
12428
12429
12430 do {
12431 found = 0;
12432 for (pos = first; pos < nPix; pos++) {
12433 if (cosmic[pos] == -1) {
12434 cosmic[pos] = 2;
12435 i = pos % xLen;
12436 j = pos / xLen;
12437 first = pos;
12438 first++;
12439 found = 1;
12440 break;
12441 }
12442 }
12443
12444 if (found) {
12445
12446
12447
12448
12449
12450
12451
12452
12453 iMin = iMax = iPosMax = i;
12454 jMin = jMax = jPosMax = j;
12455 fMax = idata[i + j * xLen];
12456
12457 do {
12458 foundContiguousCandidate = 0;
12459 for (l = 0; l <= 1; l++) {
12460 for (k = 0; k <= 1; k++) {
12461
12462
12463
12464
12465
12466 ii = i + k - l;
12467 jj = j + k + l - 1;
12468 if (cosmic[ii + jj * xLen] == -1) {
12469 foundContiguousCandidate = 1;
12470 cosmic[ii + jj * xLen] = 2;
12471
12472 iii = ii;
12473 jjj = jj;
12474
12475
12476
12477
12478
12479 if (ii < iMin)
12480 iMin = ii;
12481 if (ii > iMax)
12482 iMax = ii;
12483 if (jj < jMin)
12484 jMin = jj;
12485 if (jj > jMax)
12486 jMax = jj;
12487
12488 if (idata[ii + jj * xLen] > fMax) {
12489 fMax = idata[ii + jj * xLen];
12490 iPosMax = ii;
12491 jPosMax = jj;
12492 }
12493 }
12494 }
12495 }
12496
12497
12498
12499
12500
12501
12502 cosmic[i + j * xLen] = 3;
12503
12504 if (foundContiguousCandidate) {
12505
12506
12507
12508
12509
12510
12511 i = iii;
12512 j = jjj;
12513
12514
12515
12516
12517
12518 continue;
12519 }
12520
12521
12522
12523
12524
12525
12526 for (l = jMin; l <= jMax; l++) {
12527 for (k = iMin; k <= iMax; k++) {
12528 if (cosmic[k + l * xLen] == 2) {
12529 i = k;
12530 j = l;
12531 foundContiguousCandidate = 1;
12532 break;
12533 }
12534 }
12535 if (foundContiguousCandidate)
12536 break;
12537 }
12538 } while (foundContiguousCandidate);
12539
12540
12541
12542
12543
12544
12545
12546 sum = 0.;
12547 for (l = -1; l <= 1; l++) {
12548 for (k = -1; k <= 1; k++) {
12549 if (l != 0 || k != 0) {
12550 sum += idata[iPosMax + k + (jPosMax + l) * xLen];
12551 }
12552 }
12553 }
12554
12555 sum /= 8.;
12556 if (fMax > ratio * sum) {
12557 for (l = jMin - 1; l <= jMax + 1; l++) {
12558 for (k = iMin - 1; k <= iMax + 1; k++) {
12559 if (cosmic[k + l * xLen] == 3) {
12560 cosmic[k + l * xLen] = 1;
12561 numCosmic++;
12562 }
12563 }
12564 }
12565 }
12566 else {
12567 for (l = jMin - 1; l <= jMax + 1; l++) {
12568 for (k = iMin - 1; k <= iMax + 1; k++) {
12569 if (cosmic[k + l * xLen] != -1) {
12570 if (cosmic[k + l * xLen] == 1)
12571 numCosmic--;
12572 cosmic[k + l * xLen] = 0;
12573 }
12574 }
12575 }
12576 }
12577 }
12578 } while (found);
12579
12580
12581
12582
12583
12584
12585 table = cpl_table_new(numCosmic);
12586 cpl_table_new_column(table, "x", CPL_TYPE_INT);
12587 cpl_table_new_column(table, "y", CPL_TYPE_INT);
12588 cpl_table_set_column_unit(table, "x", "pixel");
12589 cpl_table_set_column_unit(table, "y", "pixel");
12590 xdata = cpl_table_get_data_int(table, "x");
12591 ydata = cpl_table_get_data_int(table, "y");
12592
12593 for (pos = 0, i = 0; pos < nPix; pos++) {
12594 if (cosmic[pos] == 1) {
12595 xdata[i] = (pos % xLen);
12596 ydata[i] = (pos / xLen);
12597 i++;
12598 }
12599 }
12600
12601 mos_clean_bad_pixels(image, table, 1);
12602
12603 cpl_free(cosmic);
12604 cpl_table_delete(table);
12605
12606 return CPL_ERROR_NONE;
12607
12608 }
12609
12610
12611 cpl_error_code mos_clean_bad_pixels(cpl_image *image, cpl_table *table,
12612 int spectral)
12613 {
12614 const char *func = "mos_clean_cosmics";
12615
12616 float *idata;
12617 int *isBadPix;
12618 int i, j, k, d;
12619 int xlen, ylen, totPix;
12620 int nBadPixels = 0;
12621 int sign, foundFirst;
12622 int *xValue = NULL;
12623 int *yValue = NULL;
12624 float save = 0.;
12625 double sumd;
12626 int cx, cy;
12627 int nPairs;
12628 float estimate[4];
12629 int sx[] = {0, 1, 1, 1};
12630 int sy[] = {1,-1, 0, 1};
12631 int searchHorizon = 100;
12632 int percent = 15;
12633
12634
12635 if (image == NULL || table == NULL)
12636 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12637
12638 if (1 != cpl_table_has_column(table, "x"))
12639 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
12640
12641 if (1 != cpl_table_has_column(table, "y"))
12642 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
12643
12644 if (CPL_TYPE_INT != cpl_table_get_column_type(table, "x"))
12645 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
12646
12647 if (CPL_TYPE_INT != cpl_table_get_column_type(table, "y"))
12648 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
12649
12650 nBadPixels = cpl_table_get_nrow(table);
12651
12652 if (nBadPixels) {
12653 xlen = cpl_image_get_size_x(image);
12654 ylen = cpl_image_get_size_y(image);
12655 idata = cpl_image_get_data(image);
12656 totPix = xlen * ylen;
12657 if (((float) nBadPixels) / ((float) totPix) < percent/100.) {
12658 isBadPix = cpl_calloc(totPix, sizeof(int));
12659 }
12660 else {
12661 cpl_msg_warning(func, "Too many bad pixels (> %d%%): "
12662 "skip bad pixel correction", percent);
12663 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12664 }
12665 }
12666 else {
12667 cpl_msg_debug(func, "No pixel values to interpolate");
12668 return CPL_ERROR_NONE;
12669 }
12670
12671 xValue = cpl_table_get_data_int(table, "x");
12672 yValue = cpl_table_get_data_int(table, "y");
12673
12674 for (i = 0; i < nBadPixels; i++)
12675 isBadPix[xValue[i] + yValue[i] * xlen] = 1;
12676
12677 for (i = 0; i < nBadPixels; i++) {
12678
12679
12680
12681
12682
12683
12684
12685
12686
12687
12688
12689
12690
12691 nPairs = 0;
12692 for (j = 0; j < 4; j++) {
12693
12694 if (spectral)
12695 if (j != 2)
12696 continue;
12697
12698 estimate[nPairs] = 0.;
12699 sumd = 0.;
12700 foundFirst = 0;
12701 for (k = 0; k < 2; k++) {
12702 sign = 2 * k - 1;
12703 d = 0;
12704 cx = xValue[i];
12705 cy = yValue[i];
12706 do {
12707 cx += sign * sx[j];
12708 cy += sign * sy[j];
12709 if (cx < 0 || cx >= xlen || cy < 0 || cy >= ylen)
12710 break;
12711 d++;
12712 } while (isBadPix[cx + cy * xlen] && d < searchHorizon);
12713
12714 if (cx >= 0 && cx < xlen &&
12715 cy >= 0 && cy < ylen && d < searchHorizon) {
12716
12717
12718
12719
12720
12721 save = idata[cx + cy * xlen];
12722 estimate[nPairs] += save / d;
12723 sumd += 1. / (double) d;
12724 if (k) {
12725 estimate[nPairs] /= sumd;
12726 nPairs++;
12727 }
12728 else {
12729 foundFirst = 1;
12730 }
12731 }
12732 else {
12733
12734
12735
12736
12737
12738 if (k) {
12739 if (foundFirst) {
12740 estimate[nPairs] = save;
12741 nPairs++;
12742 }
12743 }
12744 }
12745 }
12746 }
12747
12748
12749
12750
12751
12752
12753
12754 if (nPairs > 2) {
12755 idata[xValue[i] + yValue[i] * xlen] =
12756 cpl_tools_get_median_float(estimate, nPairs);
12757 }
12758 else if (nPairs == 2) {
12759 idata[xValue[i] + yValue[i] * xlen] =
12760 (estimate[0] + estimate[1]) / 2.;
12761 }
12762 else if (nPairs == 1) {
12763 idata[xValue[i] + yValue[i] * xlen] = estimate[0];
12764 }
12765 else {
12766 cpl_msg_debug(func, "Cannot correct bad pixel %d,%d\n",
12767 xValue[i], yValue[i]);
12768 }
12769 }
12770
12771 cpl_free(isBadPix);
12772
12773 return CPL_ERROR_NONE;
12774 }
12775
12776
12806 cpl_image *mos_spatial_map(cpl_image *spectra, cpl_table *slits,
12807 cpl_table *polytraces, double reference,
12808 double blue, double red, double dispersion)
12809 {
12810 const char *func = "mos_spatial_map";
12811
12812 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
12813
12814 cpl_polynomial *polytop;
12815 cpl_polynomial *polybot;
12816 cpl_image *calibration;
12817 float *data;
12818 double top, bot;
12819 double coeff;
12820 double ytop, ybot;
12821 double ypos, yfra;
12822 double factor;
12823 int yint, yprev;
12824 int nslits;
12825 int npseudo;
12826 int *slit_id;
12827 int *length;
12828 int nx, ny;
12829 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
12830 int missing_top, missing_bot;
12831 int null;
12832 int order;
12833 int i, j, k;
12834
12835
12836 if (spectra == NULL || slits == NULL || polytraces == NULL) {
12837 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12838 return NULL;
12839 }
12840
12841 if (dispersion <= 0.0) {
12842 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12843 return NULL;
12844 }
12845
12846 if (red - blue < dispersion) {
12847 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12848 return NULL;
12849 }
12850
12851 nx = cpl_image_get_size_x(spectra);
12852 ny = cpl_image_get_size_y(spectra);
12853
12854 calibration = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12855 data = cpl_image_get_data(calibration);
12856
12857 length = cpl_table_get_data_int(slits, "length");
12858 nslits = cpl_table_get_nrow(slits);
12859 slit_id = cpl_table_get_data_int(slits, "slit_id");
12860 order = cpl_table_get_ncol(polytraces) - 2;
12861
12862
12863
12864
12865
12866
12867 pixel_above = (red - reference) / dispersion;
12868 pixel_below = (reference - blue) / dispersion;
12869
12870 for (i = 0; i < nslits; i++) {
12871
12872 if (length[i] == 0)
12873 continue;
12874
12875
12876
12877
12878
12879
12880
12881
12882
12883
12884
12885
12886 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
12887
12888 start_pixel = refpixel - pixel_below;
12889 if (start_pixel < 0)
12890 start_pixel = 0;
12891
12892 end_pixel = refpixel + pixel_above;
12893 if (end_pixel > nx)
12894 end_pixel = nx;
12895
12896
12897
12898
12899
12900
12901 missing_top = 0;
12902 polytop = cpl_polynomial_new(1);
12903 for (k = 0; k <= order; k++) {
12904 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
12905 if (null) {
12906 cpl_polynomial_delete(polytop);
12907 missing_top = 1;
12908 break;
12909 }
12910 cpl_polynomial_set_coeff(polytop, &k, coeff);
12911 }
12912
12913 missing_bot = 0;
12914 polybot = cpl_polynomial_new(1);
12915 for (k = 0; k <= order; k++) {
12916 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
12917 if (null) {
12918 cpl_polynomial_delete(polybot);
12919 missing_bot = 1;
12920 break;
12921 }
12922 cpl_polynomial_set_coeff(polybot, &k, coeff);
12923 }
12924
12925 if (missing_top && missing_bot) {
12926 cpl_msg_warning(func, "Spatial map, slit %d was not traced!",
12927 slit_id[i]);
12928 continue;
12929 }
12930
12931
12932
12933
12934
12935
12936
12937 if (missing_top) {
12938 cpl_msg_warning(func, "Upper edge of slit %d was not traced: "
12939 "the spectral curvature of the lower edge "
12940 "is used instead.", slit_id[i]);
12941 polytop = cpl_polynomial_duplicate(polybot);
12942 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
12943 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
12944 k = 0;
12945 coeff = cpl_polynomial_get_coeff(polybot, &k);
12946 coeff += ytop - ybot;
12947 cpl_polynomial_set_coeff(polytop, &k, coeff);
12948 }
12949
12950 if (missing_bot) {
12951 cpl_msg_warning(func, "Lower edge of slit %d was not traced: "
12952 "the spectral curvature of the upper edge "
12953 "is used instead.", slit_id[i]);
12954 polybot = cpl_polynomial_duplicate(polytop);
12955 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
12956 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
12957 k = 0;
12958 coeff = cpl_polynomial_get_coeff(polytop, &k);
12959 coeff -= ytop - ybot;
12960 cpl_polynomial_set_coeff(polybot, &k, coeff);
12961 }
12962
12963 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
12964 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
12965 npseudo = ceil(top-bot) + 1;
12966
12967 if (npseudo < 1) {
12968 cpl_polynomial_delete(polytop);
12969 cpl_polynomial_delete(polybot);
12970 cpl_msg_warning(func, "Slit %d was badly traced: no extraction!",
12971 slit_id[i]);
12972 continue;
12973 }
12974
12975 for (j = start_pixel; j < end_pixel; j++) {
12976 top = cpl_polynomial_eval_1d(polytop, j, NULL);
12977 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
12978 factor = (top-bot)/npseudo;
12979 for (k = 0; k <= npseudo; k++) {
12980 ypos = top - k*factor;
12981 yint = ypos;
12982 yfra = ypos - yint;
12983 if (yint >= 0 && yint < ny-1) {
12984 data[j + nx*yint] = (top-yint)/factor;
12985 if (k) {
12986
12987
12988
12989
12990
12991
12992
12993 if (yprev - yint > 1) {
12994 data[j + nx*(yint+1)] = (top-yint-1)/factor;
12995 }
12996 }
12997 }
12998 yprev = yint;
12999 }
13000 }
13001 cpl_polynomial_delete(polytop);
13002 cpl_polynomial_delete(polybot);
13003 }
13004
13005 return calibration;
13006 }
13007
13008
13071 cpl_image *mos_detect_objects(cpl_image *image, cpl_table *slits, int margin,
13072 int maxradius, int conradius)
13073 {
13074 const char *func = "mos_detect_objects";
13075
13076 cpl_image *profile;
13077 float *pdata;
13078 float *p;
13079
13080 char name[MAX_COLNAME];
13081
13082 int nslits;
13083 int npeaks;
13084 int nobjects, objpos, totobj;
13085 int maxobjects;
13086 int *position;
13087 int *length;
13088 int *reject;
13089 double *place;
13090 double *bright;
13091 double mindistance;
13092 int pos, count;
13093 int up;
13094 int low, hig;
13095 int row;
13096 int i, j, k;
13097
13098 const int min_pixels = 10;
13099
13100
13101 if (cpl_error_get_code() != CPL_ERROR_NONE)
13102 return NULL;
13103
13104 if (image == NULL || slits == NULL) {
13105 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13106 return NULL;
13107 }
13108
13109 if (margin < 0)
13110 margin = 0;
13111
13112 if (maxradius < 0) {
13113 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13114 return NULL;
13115 }
13116
13117 if (conradius < 0) {
13118 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13119 return NULL;
13120 }
13121
13122 nslits = cpl_table_get_nrow(slits);
13123 position = cpl_table_get_data_int(slits, "position");
13124 length = cpl_table_get_data_int(slits, "length");
13125
13126 profile = cpl_image_collapse_create(image, 1);
13127 cpl_image_divide_scalar(profile, cpl_image_get_size_x(image));
13128 pdata = cpl_image_get_data(profile);
13129
13130 row = 1;
13131 maxobjects = 0;
13132 totobj = 0;
13133 for (i = 0; i < nslits; i++) {
13134
13135 if (length[i] == 0)
13136 continue;
13137
13138 pos = position[i] + margin;
13139 count = length[i] - 2*margin;
13140
13141 if (count < min_pixels)
13142 continue;
13143
13144 p = pdata + pos;
13145
13146
13147
13148
13149
13150
13151 npeaks = 0;
13152 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
13153 npeaks++;
13154 }
13155
13156 up = 0;
13157 for (j = 0; j < count - 3; j++) {
13158 if (p[j] > 0) {
13159 if (p[j+1] > p[j]) {
13160 up++;
13161 }
13162 else {
13163 if (up > 2) {
13164 if (p[j+1] > p[j+2] && p[j+2] > 0) {
13165 if (p[j] > 5)
13166 npeaks++;
13167 }
13168 }
13169 else if (up > 1) {
13170 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
13171 if (p[j] > 5)
13172 npeaks++;
13173 }
13174 }
13175 up = 0;
13176 }
13177 }
13178 else {
13179 up = 0;
13180 }
13181 }
13182
13183 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
13184 && p[count-3] > p[count-4] && p[count-4] > 0) {
13185 npeaks++;
13186 }
13187
13188 if (npeaks == 0)
13189 continue;
13190
13191
13192
13193
13194
13195
13196 reject = cpl_calloc(npeaks, sizeof(int));
13197 bright = cpl_calloc(npeaks, sizeof(double));
13198 place = cpl_calloc(npeaks, sizeof(double));
13199
13200 npeaks = 0;
13201 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
13202 bright[0] = p[0];
13203 place[0] = position[i] + margin;
13204 npeaks++;
13205 }
13206
13207 up = 0;
13208 for (j = 0; j < count - 3; j++) {
13209 if (p[j] > 0) {
13210 if (p[j+1] > p[j]) {
13211 up++;
13212 }
13213 else {
13214 if (up > 2) {
13215 if (p[j+1] > p[j+2] && p[j+2] > 0) {
13216 if (p[j] > 5) {
13217 bright[npeaks] = p[j];
13218 place[npeaks] = position[i] + margin + j + 1
13219 + values_to_dx(p[j-1], p[j], p[j+1]);
13220 npeaks++;
13221 }
13222 }
13223 }
13224 else if (up > 1) {
13225 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
13226 if (p[j] > 5) {
13227 bright[npeaks] = p[j];
13228 place[npeaks] = position[i] + margin + j + 1
13229 + values_to_dx(p[j-1], p[j], p[j+1]);
13230 npeaks++;
13231 }
13232 }
13233 }
13234 up = 0;
13235 }
13236 }
13237 else {
13238 up = 0;
13239 }
13240 }
13241
13242 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
13243 && p[count-3] > p[count-4] && p[count-4] > 0) {
13244 bright[npeaks] = p[count-1];
13245 place[npeaks] = position[i] + count;
13246 npeaks++;
13247 }
13248
13249
13250
13251
13252
13253
13254 if (fabs(place[0] - pos) < 1.0)
13255 reject[0] = 1;
13256 if (fabs(place[npeaks-1] - pos - count) < 1.0)
13257 reject[npeaks-1] = 1;
13258 for (j = 0; j < npeaks; j++) {
13259 for (k = 0; k < npeaks; k++) {
13260 if (k == j)
13261 continue;
13262 mindistance = conradius * bright[k] / bright[j]
13263 * bright[k] / bright[j];
13264 if (fabs(place[j] - place[k]) < mindistance)
13265 reject[j] = 1;
13266 }
13267 }
13268
13269
13270 for (j = 0; j < npeaks; j++) {
13271 if (reject[j])
13272 continue;
13273 if (j) {
13274 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
13275 / (bright[j-1] + bright[j]) + 1;
13276 }
13277 else {
13278 low = pos;
13279 }
13280 if (j < npeaks - 1) {
13281 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
13282 / (bright[j+1] + bright[j]) + 1;
13283 }
13284 else {
13285 hig = pos + count;
13286 }
13287
13288 if (low < pos)
13289 low = pos;
13290 if (hig > pos + count)
13291 hig = pos + count;
13292 if (place[j] - low > maxradius)
13293 low = place[j] - maxradius;
13294 if (hig - place[j] > maxradius)
13295 hig = place[j] + maxradius;
13296 if (hig == low)
13297 reject[j] = 1;
13298 }
13299
13300
13301 nobjects = npeaks;
13302 for (j = 0; j < npeaks; j++)
13303 if (reject[j])
13304 nobjects--;
13305
13306 for (j = 0; j < nobjects; j++) {
13307 snprintf(name, MAX_COLNAME, "object_%d", j+1);
13308 if (cpl_table_has_column(slits, name))
13309 continue;
13310 cpl_table_new_column(slits, name, CPL_TYPE_DOUBLE);
13311 snprintf(name, MAX_COLNAME, "start_%d", j+1);
13312 cpl_table_new_column(slits, name, CPL_TYPE_INT);
13313 cpl_table_set_column_unit(slits, name, "pixel");
13314 snprintf(name, MAX_COLNAME, "end_%d", j+1);
13315 cpl_table_new_column(slits, name, CPL_TYPE_INT);
13316 cpl_table_set_column_unit(slits, name, "pixel");
13317 snprintf(name, MAX_COLNAME, "row_%d", j+1);
13318 cpl_table_new_column(slits, name, CPL_TYPE_INT);
13319 cpl_table_set_column_unit(slits, name, "pixel");
13320 }
13321
13322 objpos = nobjects;
13323 for (j = 0; j < npeaks; j++) {
13324 if (reject[j])
13325 continue;
13326 if (j) {
13327 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
13328 / (bright[j-1] + bright[j]) + 1;
13329 }
13330 else {
13331 low = pos;
13332 }
13333 if (j < npeaks - 1) {
13334 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
13335 / (bright[j+1] + bright[j]) + 1;
13336 }
13337 else {
13338 hig = pos + count;
13339 }
13340
13341 if (low < pos)
13342 low = pos;
13343 if (hig > pos + count)
13344 hig = pos + count;
13345 if (place[j] - low > maxradius)
13346 low = place[j] - maxradius;
13347 if (hig - place[j] > maxradius)
13348 hig = place[j] + maxradius;
13349
13350 snprintf(name, MAX_COLNAME, "object_%d", objpos);
13351 cpl_table_set_double(slits, name, i, place[j]);
13352 snprintf(name, MAX_COLNAME, "start_%d", objpos);
13353 cpl_table_set_int(slits, name, i, low);
13354 snprintf(name, MAX_COLNAME, "end_%d", objpos);
13355 cpl_table_set_int(slits, name, i, hig);
13356 snprintf(name, MAX_COLNAME, "row_%d", objpos);
13357 cpl_table_set_int(slits, name, i, row + objpos - 1);
13358 totobj++;
13359 objpos--;
13360 }
13361
13362 row += nobjects;
13363
13364 if (maxobjects < nobjects)
13365 maxobjects = nobjects;
13366
13367 cpl_free(reject);
13368 cpl_free(bright);
13369 cpl_free(place);
13370
13371 }
13372
13373
13374 row = cpl_table_get_nrow(slits);
13375
13376 for (i = 0; i < row; i++) {
13377 for (j = 0; j < maxobjects; j++) {
13378 snprintf(name, MAX_COLNAME, "row_%d", j+1);
13379 if (cpl_table_is_valid(slits, name, i))
13380 cpl_table_set_int(slits, name, i, totobj -
13381 cpl_table_get_int(slits, name, i, NULL));
13382 }
13383 }
13384
13385 for (i = 0; i < maxobjects; i++) {
13386 snprintf(name, MAX_COLNAME, "start_%d", i+1);
13387 cpl_table_fill_invalid_int(slits, name, -1);
13388 snprintf(name, MAX_COLNAME, "end_%d", i+1);
13389 cpl_table_fill_invalid_int(slits, name, -1);
13390 snprintf(name, MAX_COLNAME, "row_%d", i+1);
13391 cpl_table_fill_invalid_int(slits, name, -1);
13392 }
13393
13394 return profile;
13395 }
13396
13397
13422 cpl_image **mos_extract_objects(cpl_image *science, cpl_image *sky,
13423 cpl_table *objects, int extraction, double ron,
13424 double gain, int ncombined)
13425 {
13426 const char *func = "mos_extract_objects";
13427
13428 char name[MAX_COLNAME];
13429
13430 cpl_image **output;
13431 cpl_image *extracted;
13432 cpl_image *extr_sky;
13433 cpl_image *error;
13434 cpl_image *sciwin;
13435 cpl_image *skywin;
13436 int nslits;
13437 int nobjects;
13438 int maxobjects;
13439 int nx, ny;
13440 int ylow, yhig;
13441 int i, j;
13442
13443
13444 if (science == NULL || sky == NULL) {
13445 cpl_msg_error(func, "Both scientific exposures are required in input");
13446 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13447 return NULL;
13448 }
13449
13450 if (objects == NULL) {
13451 cpl_msg_error(func, "An object table is required in input");
13452 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13453 return NULL;
13454 }
13455
13456 if (extraction < 0 || extraction > 1) {
13457 cpl_msg_error(func, "Invalid extraction mode (%d): it should be "
13458 "either 0 or 1", extraction);
13459 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13460 return NULL;
13461 }
13462
13463 if (ron < 0.0) {
13464 cpl_msg_error(func, "Invalid read-out-noise (%f ADU)", ron);
13465 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13466 return NULL;
13467 }
13468
13469 if (gain < 0.1) {
13470 cpl_msg_error(func, "Invalid gain factor (%f e-/ADU)", gain);
13471 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13472 return NULL;
13473 }
13474
13475 if (ncombined < 1) {
13476 cpl_msg_error(func, "Invalid number of combined frames (%d): "
13477 "it should be at least 1", ncombined);
13478 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13479 return NULL;
13480 }
13481
13482
13483
13484
13485
13486
13487
13488 maxobjects = 1;
13489 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
13490 while (cpl_table_has_column(objects, name)) {
13491 maxobjects++;
13492 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
13493 }
13494
13495
13496
13497
13498
13499
13500 nobjects = 0;
13501 nslits = cpl_table_get_nrow(objects);
13502
13503 for (i = 0; i < nslits; i++) {
13504 for (j = 1; j < maxobjects; j++) {
13505 snprintf(name, MAX_COLNAME, "object_%d", j);
13506 if (cpl_table_is_valid(objects, name, i))
13507 nobjects++;
13508 }
13509 }
13510
13511 if (nobjects == 0)
13512 return NULL;
13513
13514 nx = cpl_image_get_size_x(science);
13515 ny = cpl_image_get_size_x(science);
13516
13517 output = cpl_calloc(3, sizeof(cpl_image *));
13518 extracted = output[0] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
13519 extr_sky = output[1] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
13520 error = output[2] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
13521
13522
13523
13524
13525
13526
13527 nobjects = 0;
13528 for (i = 0; i < nslits; i++) {
13529 for (j = 1; j < maxobjects; j++) {
13530 snprintf(name, MAX_COLNAME, "object_%d", j);
13531 if (cpl_table_is_valid(objects, name, i)) {
13532 snprintf(name, MAX_COLNAME, "start_%d", j);
13533 ylow = cpl_table_get_int(objects, name, i, NULL);
13534 snprintf(name, MAX_COLNAME, "end_%d", j);
13535 yhig = cpl_table_get_int(objects, name, i, NULL);
13536 snprintf(name, MAX_COLNAME, "row_%d", j);
13537 nobjects = cpl_table_get_int(objects, name, i, NULL);
13538 sciwin = cpl_image_extract(science, 1, ylow+1, nx, yhig);
13539 skywin = cpl_image_extract(sky, 1, ylow+1, nx, yhig);
13540
13541
13542
13543
13544
13545
13546
13547
13548 mos_extraction(sciwin, skywin, extracted, extr_sky, error,
13549 nobjects, extraction, ron, gain, ncombined);
13550 cpl_image_delete(sciwin);
13551 cpl_image_delete(skywin);
13552 nobjects++;
13553 }
13554 }
13555 }
13556
13557 return output;
13558
13559 }
13560
13561
13584 int mos_spectral_resolution(cpl_image *image, double lambda, double startwave,
13585 double dispersion, int saturation,
13586 double *mfwhm, double *rmsfwhm,
13587 double *resolution, double *rmsres, int *nlines)
13588 {
13589 cpl_vector *vector;
13590
13591 int i, j, n, m;
13592 int position, maxpos;
13593 int xlen, ylen;
13594 int sp, ep;
13595 int radius;
13596 int sradius = 40;
13597 int threshold = 250;
13598
13599 int ifwhm;
13600 double fwhm;
13601 double *buffer;
13602 double min, max, halfmax;
13603 double cut = 1.5;
13604 double value, rms;
13605
13606 float *data;
13607
13608
13609 *resolution = 0.0;
13610 *rmsres = 0.0;
13611 *nlines = 0;
13612
13613 xlen = cpl_image_get_size_x(image);
13614 ylen = cpl_image_get_size_y(image);
13615 data = cpl_image_get_data(image);
13616
13617 buffer = cpl_malloc(ylen * sizeof(double));
13618
13619
13620
13621
13622
13623 position = floor((lambda - startwave) / dispersion + 0.5);
13624
13625 sp = position - sradius;
13626 ep = position + sradius;
13627
13628 if (sp < 0 || ep > xlen) {
13629 cpl_free(buffer);
13630 return 0;
13631 }
13632
13633 for (i = 0, n = 0; i < ylen; i++) {
13634
13635
13636
13637
13638
13639 radius = mos_lines_width(data + i*xlen + position - sradius,
13640 2*sradius + 1);
13641 if (radius < 5)
13642 radius = 5;
13643
13644 sp = position - radius;
13645 ep = position + radius;
13646
13647 if (sp < 0 || ep > xlen) {
13648 cpl_free(buffer);
13649 return 0;
13650 }
13651
13652
13653
13654
13655
13656
13657 maxpos = sp;
13658 min = max = data[sp + i * xlen];
13659 for (j = sp; j < ep; j++) {
13660 if (data[j + i * xlen] > max) {
13661 max = data[j + i * xlen];
13662 maxpos = j;
13663 }
13664 if (data[j + i * xlen] < min) {
13665 min = data[j + i * xlen];
13666 }
13667 }
13668
13669 if (fabs(min) < 0.0000001)
13670 continue;
13671
13672 if (max - min < threshold)
13673 continue;
13674
13675 if (max > saturation)
13676 continue;
13677
13678
13679
13680
13681
13682
13683
13684
13685 halfmax = (max + min)/ 2.0;
13686
13687 fwhm = 0.0;
13688 ifwhm = 0;
13689 for (j = maxpos; j < maxpos + radius; j++) {
13690 if (j < xlen) {
13691 if (data[j + i * xlen] < halfmax) {
13692 fwhm = ifwhm + (data[j - 1 + i * xlen] - halfmax)
13693 / (data[j - 1 + i * xlen] - data[j + i * xlen]);
13694 break;
13695 }
13696 ifwhm++;
13697 }
13698 }
13699
13700 ifwhm = 0;
13701 for (j = maxpos; j > maxpos - radius; j--) {
13702 if (j >= 0) {
13703 if (data[j + i * xlen] < halfmax) {
13704 fwhm += ifwhm + (data[j + 1 + i * xlen] - halfmax)
13705 / (data[j + 1 + i * xlen] - data[j + i * xlen]);
13706 break;
13707 }
13708 ifwhm++;
13709 }
13710 }
13711
13712 if (fwhm > 3.0) {
13713 buffer[n] = fwhm - 2.0;
13714 n++;
13715 }
13716
13717 }
13718
13719 if (n == 0) {
13720 cpl_free(buffer);
13721 return 0;
13722 }
13723
13724 vector = cpl_vector_wrap(n, buffer);
13725 value = cpl_vector_get_median_const(vector);
13726 cpl_vector_unwrap(vector);
13727
13728 rms = 0.0;
13729 for (i = 0, m = 0; i < n; i++) {
13730 if (fabs(buffer[i] - value) < cut) {
13731 rms += fabs(buffer[i] - value);
13732 m++;
13733 }
13734 }
13735
13736 cpl_free(buffer);
13737
13738 if (m < 3)
13739 return 0;
13740
13741 rms /= m;
13742 rms *= 1.25;
13743
13744 value *= dispersion;
13745 rms *= dispersion;
13746
13747 *mfwhm = value;
13748 *rmsfwhm = rms;
13749
13750 *resolution = lambda / value;
13751 *rmsres = *resolution * rms / value;
13752
13753 *nlines = m;
13754
13755 return 1;
13756 }
13757
13758
13780 cpl_table *mos_resolution_table(cpl_image *image, double startwave,
13781 double dispersion, int saturation,
13782 cpl_vector *lines)
13783 {
13784
13785 cpl_table *table;
13786 double *line;
13787 double fwhm;
13788 double rmsfwhm;
13789 double resolution;
13790 double rmsres;
13791 int nref;
13792 int nlines;
13793 int i;
13794
13795
13796 nref = cpl_vector_get_size(lines);
13797 line = cpl_vector_get_data(lines);
13798
13799 table = cpl_table_new(nref);
13800 cpl_table_new_column(table, "wavelength", CPL_TYPE_DOUBLE);
13801 cpl_table_set_column_unit(table, "wavelength", "Angstrom");
13802 cpl_table_new_column(table, "fwhm", CPL_TYPE_DOUBLE);
13803 cpl_table_set_column_unit(table, "fwhm", "Angstrom");
13804 cpl_table_new_column(table, "fwhm_rms", CPL_TYPE_DOUBLE);
13805 cpl_table_set_column_unit(table, "fwhm_rms", "Angstrom");
13806 cpl_table_new_column(table, "resolution", CPL_TYPE_DOUBLE);
13807 cpl_table_new_column(table, "resolution_rms", CPL_TYPE_DOUBLE);
13808 cpl_table_new_column(table, "nlines", CPL_TYPE_INT);
13809
13810 for (i = 0; i < nref; i++) {
13811 if (mos_spectral_resolution(image, line[i], startwave, dispersion,
13812 saturation, &fwhm, &rmsfwhm,
13813 &resolution, &rmsres, &nlines)) {
13814 cpl_table_set_double(table, "wavelength", i, line[i]);
13815 cpl_table_set_double(table, "fwhm", i, fwhm);
13816 cpl_table_set_double(table, "fwhm_rms", i, rmsfwhm);
13817 cpl_table_set_double(table, "resolution", i, resolution);
13818 cpl_table_set_double(table, "resolution_rms", i, rmsres);
13819 cpl_table_set_int(table, "nlines", i, nlines);
13820 }
13821 else
13822 cpl_table_set_int(table, "nlines", i, 0);
13823 }
13824
13825 if (cpl_table_has_valid(table, "wavelength"))
13826 return table;
13827
13828 cpl_table_delete(table);
13829
13830 return NULL;
13831
13832 }
13833
13834
13852 double mos_integrate_signal(cpl_image *image, cpl_image *wavemap,
13853 int ystart, int yend, double wstart, double wend)
13854 {
13855 const char *func = "mos_integrate_signal";
13856
13857 double sum;
13858 float *sdata;
13859 float *wdata;
13860 int nx, ny;
13861 int x, y;
13862
13863
13864 if (image == NULL || wavemap == NULL) {
13865 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13866 return 0.0;
13867 }
13868
13869 if (ystart > yend || wstart >= wend) {
13870 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13871 return 0.0;
13872 }
13873
13874 nx = cpl_image_get_size_x(image);
13875 ny = cpl_image_get_size_y(image);
13876
13877 if (!(nx == cpl_image_get_size_x(wavemap)
13878 && ny == cpl_image_get_size_y(wavemap))) {
13879 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
13880 return 0.0;
13881 }
13882
13883 if (ystart < 0 || yend > ny) {
13884 cpl_error_set(func, CPL_ERROR_ACCESS_OUT_OF_RANGE);
13885 return 0.0;
13886 }
13887
13888 sdata = cpl_image_get_data(image);
13889 wdata = cpl_image_get_data(wavemap);
13890
13891 sdata += ystart*nx;
13892 wdata += ystart*nx;
13893
13894 sum = 0.0;
13895 for (y = ystart; y < yend; y++) {
13896 for (x = 0; x < nx; x++) {
13897 if (wdata[x] < wstart || wdata[x] > wend)
13898 continue;
13899 sum += sdata[x];
13900 }
13901 sdata += nx;
13902 wdata += nx;
13903 }
13904
13905 return sum;
13906
13907 }
13908
13909
13910
13911
13912
13913
13914
13915
13916
13917
13940 cpl_table *mos_load_slits_fors_mxu(cpl_propertylist *header)
13941 {
13942 const char *func = "mos_load_slits_fors_mxu";
13943
13944 cpl_table *slits;
13945 char keyname[MAX_COLNAME];
13946 const char *instrume;
13947 const char *target_name;
13948 float slit_x;
13949 float slit_y;
13950 float length;
13951
13952 double arc2mm = 0.528;
13953 int nslits;
13954 int slit_id;
13955 int fors;
13956 int chip;
13957 int found;
13958
13959
13960
13961
13962
13963
13964
13965 float low_limit1 = 10.0;
13966 float hig_limit2 = 30.0;
13967
13968
13969 if (cpl_error_get_code() != CPL_ERROR_NONE) {
13970 return NULL;
13971 }
13972
13973 if (header == NULL) {
13974 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13975 return NULL;
13976 }
13977
13978
13979
13980
13981
13982
13983 instrume = cpl_propertylist_get_string(header, "INSTRUME");
13984
13985 fors = 0;
13986 if (instrume[4] == '1')
13987 fors = 1;
13988 if (instrume[4] == '2')
13989 fors = 2;
13990
13991 if (fors != 2) {
13992 cpl_msg_error(func, "Wrong instrument: %s\n"
13993 "FORS2 is expected for MXU data", instrume);
13994 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13995 return NULL;
13996 }
13997
13998
13999
14000
14001
14002
14003
14004
14005 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
14006
14007 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14008 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
14009 "in FITS header");
14010 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14011 return NULL;
14012 }
14013
14014 if (chip != 1 && chip != 2) {
14015 cpl_msg_error(func, "Unexpected chip position in keyword "
14016 "ESO DET CHIP1 Y: %d", chip);
14017 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14018 return NULL;
14019 }
14020
14021
14022
14023
14024
14025
14026
14027 nslits = 0;
14028 slit_id = 0;
14029 found = 1;
14030
14031 while (found) {
14032 slit_id++;
14033 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d YPOS", slit_id + 100);
14034 if (cpl_propertylist_has(header, keyname)) {
14035 slit_y = cpl_propertylist_get_double(header, keyname);
14036
14037 if (chip == 1)
14038 if (slit_y < low_limit1)
14039 continue;
14040 if (chip == 2)
14041 if (slit_y > hig_limit2)
14042 continue;
14043
14044 snprintf(keyname, MAX_COLNAME, "ESO INS TARG%d NAME",
14045 slit_id + 100);
14046 if (cpl_propertylist_has(header, keyname)) {
14047 target_name = cpl_propertylist_get_string(header, keyname);
14048 if (strncmp(target_name, "refslit", 7))
14049 nslits++;
14050 }
14051 else
14052 nslits++;
14053 }
14054 else
14055 found = 0;
14056 }
14057
14058 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14059 cpl_msg_error(func, "%s while loading slits coordinates from "
14060 "FITS header", cpl_error_get_message());
14061 cpl_error_set_where(func);
14062 return NULL;
14063 }
14064
14065 if (nslits == 0) {
14066 cpl_msg_error(func, "No slits coordinates found in header");
14067 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14068 return NULL;
14069 }
14070
14071 slits = cpl_table_new(nslits);
14072 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
14073 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
14074 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
14075 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
14076 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
14077 cpl_table_set_column_unit(slits, "xtop", "pixel");
14078 cpl_table_set_column_unit(slits, "ytop", "pixel");
14079 cpl_table_set_column_unit(slits, "xbottom", "pixel");
14080 cpl_table_set_column_unit(slits, "ybottom", "pixel");
14081
14082 nslits = 0;
14083 slit_id = 0;
14084 found = 1;
14085 while (found) {
14086 slit_id++;
14087 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d YPOS", slit_id + 100);
14088 if (cpl_propertylist_has(header, keyname)) {
14089 slit_y = cpl_propertylist_get_double(header, keyname);
14090
14091 if (chip == 1)
14092 if (slit_y < low_limit1)
14093 continue;
14094 if (chip == 2)
14095 if (slit_y > hig_limit2)
14096 continue;
14097
14098
14099
14100
14101
14102
14103 slit_y = -slit_y;
14104
14105 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d XPOS", slit_id + 100);
14106 slit_x = cpl_propertylist_get_double(header, keyname);
14107 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14108 cpl_table_delete(slits);
14109 cpl_msg_error(func, "Missing keyword %s in FITS header",
14110 keyname);
14111 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14112 return NULL;
14113 }
14114
14115 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d LEN", slit_id + 100);
14116 length = cpl_propertylist_get_double(header, keyname);
14117 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14118 cpl_table_delete(slits);
14119 cpl_msg_error(func, "Missing keyword %s in FITS header",
14120 keyname);
14121 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14122 return NULL;
14123 }
14124
14125 length *= arc2mm;
14126
14127 snprintf(keyname, MAX_COLNAME, "ESO INS TARG%d NAME",
14128 slit_id + 100);
14129 if (cpl_propertylist_has(header, keyname)) {
14130 target_name = cpl_propertylist_get_string(header, keyname);
14131 if (strncmp(target_name, "refslit", 7)) {
14132 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
14133 cpl_table_set(slits, "xtop", nslits, slit_x);
14134 cpl_table_set(slits, "ytop", nslits, slit_y + length/2);
14135 cpl_table_set(slits, "xbottom", nslits, slit_x);
14136 cpl_table_set(slits, "ybottom", nslits, slit_y - length/2);
14137 nslits++;
14138 }
14139 }
14140 else {
14141 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
14142 cpl_table_set(slits, "xtop", nslits, slit_x);
14143 cpl_table_set(slits, "ytop", nslits, slit_y + length/2);
14144 cpl_table_set(slits, "xbottom", nslits, slit_x);
14145 cpl_table_set(slits, "ybottom", nslits, slit_y - length/2);
14146 nslits++;
14147 }
14148 }
14149 else
14150 found = 0;
14151 }
14152
14153 return slits;
14154 }
14155
14156
14179 cpl_table *mos_load_slits_fors_mos(cpl_propertylist *header)
14180 {
14181 const char *func = "mos_load_slits_fors_mos";
14182
14183 cpl_table *slits;
14184 char keyname[MAX_COLNAME];
14185 const char *instrume;
14186 const char *chipname;
14187 float slit_x;
14188 int first_slit, last_slit;
14189 int nslits;
14190 int slit_id;
14191 int fors;
14192 int chip;
14193 int fors_is_old;
14194
14195
14196
14197
14198
14199 float ytop[19] = { 113.9, 101.3, 89.9, 77.3, 65.9, 53.3,
14200 41.9, 29.3, 17.9, 5.3, -6.1, -18.7,
14201 -30.1, -42.7, -54.1, -66.7, -78.1, -90.7,
14202 -102.1 };
14203 float ybottom[19] = { 102.1, 90.7, 78.1, 66.7, 54.1, 42.7,
14204 30.1, 18.7, 6.1, -5.3, -17.9, -29.3,
14205 -41.9, -53.3, -65.9, -77.3, -89.9, -101.3,
14206 -113.9 };
14207
14208
14209 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14210 return NULL;
14211 }
14212
14213 if (header == NULL) {
14214 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14215 return NULL;
14216 }
14217
14218
14219
14220
14221
14222
14223 instrume = cpl_propertylist_get_string(header, "INSTRUME");
14224
14225 fors = 0;
14226 if (instrume[4] == '1')
14227 fors = 1;
14228 if (instrume[4] == '2')
14229 fors = 2;
14230
14231 if (fors == 0) {
14232 cpl_msg_error(func, "Wrong instrument found in FITS header: %s",
14233 instrume);
14234 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14235 return NULL;
14236 }
14237
14238
14239
14240
14241
14242
14243
14244 chipname = cpl_propertylist_get_string(header, "ESO DET CHIP1 ID");
14245
14246 if (chipname[0] == 'M' || chipname[0] == 'N')
14247 fors_is_old = 0;
14248 else
14249 fors_is_old = 1;
14250
14251 if (fors == 1 && fors_is_old) {
14252 first_slit = 1;
14253 last_slit = 19;
14254 }
14255 else {
14256
14257
14258
14259
14260
14261
14262
14263 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
14264
14265 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14266 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
14267 "in FITS header");
14268 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14269 return NULL;
14270 }
14271
14272 if (chip != 1 && chip != 2) {
14273 cpl_msg_error(func, "Unexpected chip position in keyword "
14274 "ESO DET CHIP1 Y: %d", chip);
14275 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14276 return NULL;
14277 }
14278
14279 if (chip == 1) {
14280 first_slit = 12;
14281 last_slit = 19;
14282 }
14283 else {
14284 first_slit = 1;
14285 last_slit = 11;
14286 }
14287 }
14288
14289
14290
14291
14292
14293
14294
14295
14296 nslits = 0;
14297 slit_id = 0;
14298 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
14299 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d POS", slit_id);
14300 if (cpl_propertylist_has(header, keyname)) {
14301 slit_x = cpl_propertylist_get_double(header, keyname);
14302 if (fabs(slit_x) < 115.0)
14303 nslits++;
14304 }
14305 else {
14306 cpl_msg_error(func, "Missing keyword %s in FITS header", keyname);
14307 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14308 return NULL;
14309 }
14310 }
14311
14312 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14313 cpl_msg_error(func, "%s while loading slits coordinates from "
14314 "FITS header", cpl_error_get_message());
14315 cpl_error_set_where(func);
14316 return NULL;
14317 }
14318
14319 if (nslits == 0) {
14320 cpl_msg_error(func, "No slits coordinates found in header");
14321 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14322 return NULL;
14323 }
14324
14325 slits = cpl_table_new(nslits);
14326 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
14327 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
14328 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
14329 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
14330 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
14331 cpl_table_set_column_unit(slits, "xtop", "pixel");
14332 cpl_table_set_column_unit(slits, "ytop", "pixel");
14333 cpl_table_set_column_unit(slits, "xbottom", "pixel");
14334 cpl_table_set_column_unit(slits, "ybottom", "pixel");
14335
14336 nslits = 0;
14337 slit_id = 0;
14338 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
14339 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d POS", slit_id);
14340 slit_x = cpl_propertylist_get_double(header, keyname);
14341 if (fabs(slit_x) < 115.0) {
14342 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
14343 cpl_table_set(slits, "xtop", nslits, slit_x);
14344 cpl_table_set(slits, "ytop", nslits, ytop[slit_id-1]);
14345 cpl_table_set(slits, "xbottom", nslits, slit_x);
14346 cpl_table_set(slits, "ybottom", nslits, ybottom[slit_id-1]);
14347 nslits++;
14348 }
14349 }
14350
14351 return slits;
14352 }
14353
14354
14378 cpl_table *mos_load_slits_fors_lss(cpl_propertylist *header)
14379 {
14380 const char *func = "mos_load_slits_fors_lss";
14381
14382 cpl_table *slits;
14383 char *slit_name;
14384 const char *instrume;
14385 int fors;
14386 int chip;
14387 float ytop;
14388 float ybottom;
14389
14390 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14391 return NULL;
14392 }
14393
14394 if (header == NULL) {
14395 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14396 return NULL;
14397 }
14398
14399
14400
14401
14402
14403
14404 instrume = cpl_propertylist_get_string(header, "INSTRUME");
14405
14406 fors = 0;
14407 if (instrume[4] == '1')
14408 fors = 1;
14409 if (instrume[4] == '2')
14410 fors = 2;
14411
14412 if (fors == 0) {
14413 cpl_msg_error(func, "Wrong instrument found in FITS header: %s",
14414 instrume);
14415 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14416 return NULL;
14417 }
14418
14419 if (fors == 1) {
14420 ytop = 109.94;
14421 ybottom = -109.94;
14422 }
14423 else {
14424
14425
14426
14427
14428
14429
14430
14431 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
14432
14433 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14434 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
14435 "in FITS header");
14436 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14437 return NULL;
14438 }
14439
14440 if (chip != 1 && chip != 2) {
14441 cpl_msg_error(func, "Unexpected chip position in keyword "
14442 "ESO DET CHIP1 Y: %d", chip);
14443 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14444 return NULL;
14445 }
14446
14447 if (chip == 1) {
14448 ytop = 30.0;
14449 ybottom = -109.94;
14450 }
14451 else {
14452 ytop = 109.94;
14453 ybottom = -20.0;
14454 }
14455 }
14456
14457
14458 slits = cpl_table_new(1);
14459 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
14460 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
14461 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
14462 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
14463 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
14464 cpl_table_set_column_unit(slits, "xtop", "pixel");
14465 cpl_table_set_column_unit(slits, "ytop", "pixel");
14466 cpl_table_set_column_unit(slits, "xbottom", "pixel");
14467 cpl_table_set_column_unit(slits, "ybottom", "pixel");
14468
14469 slit_name = (char *)cpl_propertylist_get_string(header,
14470 "ESO INS SLIT NAME");
14471
14472 cpl_table_set(slits, "ytop", 0, ytop);
14473 cpl_table_set(slits, "ybottom", 0, ybottom);
14474
14475 if (!strncmp(slit_name, "lSlit0_3arcsec", 14)) {
14476 cpl_table_set_int(slits, "slit_id", 0, 1);
14477 cpl_table_set(slits, "xbottom", 0, -0.075);
14478 cpl_table_set(slits, "xtop", 0, 0.075);
14479 }
14480 else if (!strncmp(slit_name, "lSlit0_4arcsec", 14)) {
14481 cpl_table_set_int(slits, "slit_id", 0, 2);
14482 cpl_table_set(slits, "xbottom", 0, 5.895);
14483 cpl_table_set(slits, "xtop", 0, 6.105);
14484 }
14485 else if (!strncmp(slit_name, "lSlit0_5arcsec", 14)) {
14486 cpl_table_set_int(slits, "slit_id", 0, 3);
14487 cpl_table_set(slits, "xbottom", 0, -6.135);
14488 cpl_table_set(slits, "xtop", 0, -5.865);
14489 }
14490 else if (!strncmp(slit_name, "lSlit0_7arcsec", 14)) {
14491 cpl_table_set_int(slits, "slit_id", 0, 4);
14492 cpl_table_set(slits, "xbottom", 0, 11.815);
14493 cpl_table_set(slits, "xtop", 0, 12.185);
14494 }
14495 else if (!strncmp(slit_name, "lSlit1_0arcsec", 14)) {
14496 cpl_table_set_int(slits, "slit_id", 0, 5);
14497 cpl_table_set(slits, "xbottom", 0, -12.265);
14498 cpl_table_set(slits, "xtop", 0, -11.735);
14499 }
14500 else if (!strncmp(slit_name, "lSlit1_3arcsec", 14)) {
14501 cpl_table_set_int(slits, "slit_id", 0, 6);
14502 cpl_table_set(slits, "xbottom", 0, 17.655);
14503 cpl_table_set(slits, "xtop", 0, 18.345);
14504 }
14505 else if (!strncmp(slit_name, "lSlit1_6arcsec", 14)) {
14506 cpl_table_set_int(slits, "slit_id", 0, 7);
14507 cpl_table_set(slits, "xbottom", 0, -18.425);
14508 cpl_table_set(slits, "xtop", 0, -17.575);
14509 }
14510 else if (!strncmp(slit_name, "lSlit2_0arcsec", 14)) {
14511 cpl_table_set_int(slits, "slit_id", 0, 8);
14512 cpl_table_set(slits, "xbottom", 0, 23.475);
14513 cpl_table_set(slits, "xtop", 0, 24.525);
14514 }
14515 else if (!strncmp(slit_name, "lSlit2_5arcsec", 14)) {
14516 cpl_table_set_int(slits, "slit_id", 0, 9);
14517 cpl_table_set(slits, "xbottom", 0, -24.66);
14518 cpl_table_set(slits, "xtop", 0, -23.34);
14519 }
14520 else {
14521 cpl_msg_error(func, "Invalid slit %s in keyword ESO INS SLIT NAME",
14522 slit_name);
14523 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14524 cpl_table_delete(slits);
14525 return NULL;
14526 }
14527
14528 return slits;
14529 }
14530
14531
14546 double mos_get_gain_vimos(cpl_propertylist *header)
14547 {
14548 const char *func = "mos_get_gain_vimos";
14549
14550 double gain = -1.0;
14551
14552
14553 if (cpl_error_get_code() != CPL_ERROR_NONE)
14554 return gain;
14555
14556 if (header == NULL) {
14557 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14558 return gain;
14559 }
14560
14561 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
14562 if (cpl_error_get_code()) {
14563 cpl_error_set_where(func);
14564 gain = -1.0;
14565 }
14566
14567 return gain;
14568
14569 }
14570
14571
14591 cpl_table *mos_load_slits_vimos(cpl_propertylist *header)
14592 {
14593 const char *func = "mos_load_slits_vimos";
14594
14595 cpl_table *slits;
14596 char keyname[MAX_COLNAME];
14597 float slit_x;
14598 float slit_y;
14599 float dim_x;
14600 int nslits;
14601 int slit_id;
14602 int i;
14603
14604
14605 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14606 return NULL;
14607 }
14608
14609 if (header == NULL) {
14610 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14611 return NULL;
14612 }
14613
14614 nslits = cpl_propertylist_get_int(header, "ESO INS SLIT NO");
14615
14616 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14617 cpl_error_set_where(func);
14618 return NULL;
14619 }
14620
14621 slits = cpl_table_new(nslits);
14622 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
14623 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
14624 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
14625 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
14626 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
14627 cpl_table_set_column_unit(slits, "xtop", "pixel");
14628 cpl_table_set_column_unit(slits, "ytop", "pixel");
14629 cpl_table_set_column_unit(slits, "xbottom", "pixel");
14630 cpl_table_set_column_unit(slits, "ybottom", "pixel");
14631
14632 for (i = 0; i < nslits; i++) {
14633 sprintf(keyname, "ESO INS SLIT%d ID", i+1);
14634 slit_id = cpl_propertylist_get_int(header, keyname);
14635 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14636 cpl_error_set_where(func);
14637 return NULL;
14638 }
14639 sprintf(keyname, "ESO INS SLIT%d X", i+1);
14640 slit_x = cpl_propertylist_get_double(header, keyname);
14641 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14642 cpl_error_set_where(func);
14643 return NULL;
14644 }
14645 sprintf(keyname, "ESO INS SLIT%d Y", i+1);
14646 slit_y = cpl_propertylist_get_double(header, keyname);
14647 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14648 cpl_error_set_where(func);
14649 return NULL;
14650 }
14651 sprintf(keyname, "ESO INS SLIT%d DIMX", i+1);
14652 dim_x = cpl_propertylist_get_double(header, keyname) / 2;
14653 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14654 cpl_error_set_where(func);
14655 return NULL;
14656 }
14657 cpl_table_set_int(slits, "slit_id", i, slit_id);
14658 cpl_table_set(slits, "xtop", i, slit_x - dim_x);
14659 cpl_table_set(slits, "ytop", i, slit_y);
14660 cpl_table_set(slits, "xbottom", i, slit_x + dim_x);
14661 cpl_table_set(slits, "ybottom", i, slit_y);
14662 }
14663
14664 return slits;
14665 }
14666
14667
14694 cpl_table *mos_load_overscans_vimos(const cpl_propertylist *header,
14695 int check_consistency)
14696 {
14697 const char *func = "mos_load_overscans_vimos";
14698
14699 int nx = 0;
14700 int ny = 0;
14701 int px = 0;
14702 int py = 0;
14703 int ox = 0;
14704 int oy = 0;
14705 int vx = 0;
14706 int vy = 0;
14707 int nrows;
14708 cpl_table *overscans;
14709
14710
14711 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14712 cpl_msg_error(func, "Reset your error: %s", cpl_error_get_message());
14713 return NULL;
14714 }
14715
14716 if (header == NULL) {
14717 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14718 return NULL;
14719 }
14720
14721 if (cpl_propertylist_has(header, "NAXIS1"))
14722 nx = cpl_propertylist_get_int(header, "NAXIS1");
14723 if (cpl_propertylist_has(header, "NAXIS2"))
14724 ny = cpl_propertylist_get_int(header, "NAXIS2");
14725 if (cpl_propertylist_has(header, "ESO DET OUT1 PRSCX"))
14726 px = cpl_propertylist_get_int(header, "ESO DET OUT1 PRSCX");
14727 if (cpl_propertylist_has(header, "ESO DET OUT1 PRSCY"))
14728 py = cpl_propertylist_get_int(header, "ESO DET OUT1 PRSCY");
14729 if (cpl_propertylist_has(header, "ESO DET OUT1 OVSCX"))
14730 ox = cpl_propertylist_get_int(header, "ESO DET OUT1 OVSCX");
14731 if (cpl_propertylist_has(header, "ESO DET OUT1 OVSCY"))
14732 oy = cpl_propertylist_get_int(header, "ESO DET OUT1 OVSCY");
14733 if (cpl_propertylist_has(header, "ESO DET OUT1 NX"))
14734 vx = cpl_propertylist_get_int(header, "ESO DET OUT1 NX");
14735 if (cpl_propertylist_has(header, "ESO DET OUT1 NY"))
14736 vy = cpl_propertylist_get_int(header, "ESO DET OUT1 NY");
14737
14738 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14739 cpl_msg_error(func, "Missing overscan keywords in header");
14740 cpl_error_set_where(func);
14741 return NULL;
14742 }
14743
14744 if (px < 0 || py < 0 || ox < 0 || oy < 0) {
14745 cpl_msg_error(func, "Missing overscan keywords in header");
14746 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14747 return NULL;
14748 }
14749
14750 if ((px + vx + ox != nx) || (py + vy + oy != ny)) {
14751 if (check_consistency) {
14752 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14753 return NULL;
14754 }
14755 else {
14756 cpl_msg_debug(func, "Overscans description conflicts with "
14757 "reported image sizes, "
14758 "%d + %d + %d != %d or "
14759 "%d + %d + %d != %d",
14760 px, vx, ox, nx,
14761 py, vy, oy, ny);
14762 }
14763 }
14764
14765 nrows = 0;
14766 if (px > 0)
14767 nrows++;
14768 if (ox > 0)
14769 nrows++;
14770 if (py > 0)
14771 nrows++;
14772 if (oy > 0)
14773 nrows++;
14774
14775 if (nrows > 2) {
14776 cpl_msg_error(func, "Unexpected overscan regions "
14777 "(both in X and Y direction)");
14778 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14779 return NULL;
14780 }
14781
14782
14783
14784
14785
14786
14787
14788 nrows++;
14789
14790 overscans = cpl_table_new(nrows);
14791 cpl_table_new_column(overscans, "xlow", CPL_TYPE_INT);
14792 cpl_table_new_column(overscans, "ylow", CPL_TYPE_INT);
14793 cpl_table_new_column(overscans, "xhig", CPL_TYPE_INT);
14794 cpl_table_new_column(overscans, "yhig", CPL_TYPE_INT);
14795
14796 nrows = 0;
14797
14798 cpl_table_set_int(overscans, "xlow", nrows, px);
14799 cpl_table_set_int(overscans, "ylow", nrows, py);
14800 cpl_table_set_int(overscans, "xhig", nrows, nx - ox);
14801 cpl_table_set_int(overscans, "yhig", nrows, ny - oy);
14802 nrows++;
14803
14804 if (px > 0) {
14805 cpl_table_set_int(overscans, "xlow", nrows, 0);
14806 cpl_table_set_int(overscans, "ylow", nrows, 0);
14807 cpl_table_set_int(overscans, "xhig", nrows, px);
14808 cpl_table_set_int(overscans, "yhig", nrows, ny);
14809 nrows++;
14810 }
14811
14812 if (ox > 0) {
14813 cpl_table_set_int(overscans, "xlow", nrows, nx - ox);
14814 cpl_table_set_int(overscans, "ylow", nrows, 0);
14815 cpl_table_set_int(overscans, "xhig", nrows, nx);
14816 cpl_table_set_int(overscans, "yhig", nrows, ny);
14817 nrows++;
14818 }
14819
14820 if (py > 0) {
14821 cpl_table_set_int(overscans, "xlow", nrows, 0);
14822 cpl_table_set_int(overscans, "ylow", nrows, 0);
14823 cpl_table_set_int(overscans, "xhig", nrows, nx);
14824 cpl_table_set_int(overscans, "yhig", nrows, py);
14825 nrows++;
14826 }
14827
14828 if (oy > 0) {
14829 cpl_table_set_int(overscans, "xlow", nrows, 0);
14830 cpl_table_set_int(overscans, "ylow", nrows, ny - oy);
14831 cpl_table_set_int(overscans, "xhig", nrows, nx);
14832 cpl_table_set_int(overscans, "yhig", nrows, ny);
14833 nrows++;
14834 }
14835
14836 return overscans;
14837
14838 }
14839
14840
14841 cpl_table *mos_load_overscans_fors(const cpl_propertylist *header)
14842 {
14843 const char *func = "mos_load_overscans_fors";
14844
14845 int nports;
14846 int nx = 0;
14847 int ny = 0;
14848 int px = 0;
14849 int py = 0;
14850 int ox = 0;
14851 int oy = 0;
14852 int rebin;
14853 int nrows;
14854 cpl_table *overscans;
14855
14856
14857 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14858 cpl_msg_error(func, "Reset your error: %s", cpl_error_get_message());
14859 return NULL;
14860 }
14861
14862 if (header == NULL) {
14863 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14864 return NULL;
14865 }
14866
14867 if (cpl_propertylist_has(header, "ESO DET OUTPUTS"))
14868 nports = cpl_propertylist_get_int(header, "ESO DET OUTPUTS");
14869
14870 if (nports == 4 &&
14871 cpl_propertylist_has(header, "ESO DET OUT1 PRSCX") &&
14872 cpl_propertylist_has(header, "ESO DET WIN1 BINX")) {
14873
14874 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
14875
14876 overscans = cpl_table_new(3);
14877 cpl_table_new_column(overscans, "xlow", CPL_TYPE_INT);
14878 cpl_table_new_column(overscans, "ylow", CPL_TYPE_INT);
14879 cpl_table_new_column(overscans, "xhig", CPL_TYPE_INT);
14880 cpl_table_new_column(overscans, "yhig", CPL_TYPE_INT);
14881
14882 px = 16 / rebin;
14883 ox = 16 / rebin;
14884 nx = 2080 / rebin;
14885 ny = 2048 / rebin;
14886 nrows = 0;
14887
14888 cpl_table_set_int(overscans, "xlow", nrows, px);
14889 cpl_table_set_int(overscans, "ylow", nrows, py);
14890 cpl_table_set_int(overscans, "xhig", nrows, nx - ox);
14891 cpl_table_set_int(overscans, "yhig", nrows, ny - oy);
14892 nrows++;
14893
14894 cpl_table_set_int(overscans, "xlow", nrows, 0);
14895 cpl_table_set_int(overscans, "ylow", nrows, 0);
14896 cpl_table_set_int(overscans, "xhig", nrows, px);
14897 cpl_table_set_int(overscans, "yhig", nrows, ny);
14898 nrows++;
14899
14900 cpl_table_set_int(overscans, "xlow", nrows, nx - ox);
14901 cpl_table_set_int(overscans, "ylow", nrows, 0);
14902 cpl_table_set_int(overscans, "xhig", nrows, nx);
14903 cpl_table_set_int(overscans, "yhig", nrows, ny);
14904 nrows++;
14905 }
14906 else {
14907 overscans = mos_load_overscans_vimos(header, 0);
14908 }
14909
14910 return overscans;
14911
14912 }
14913
14945 #define READY 1
14946 #ifdef READY
14947
14948 cpl_polynomial *mos_montecarlo_polyfit(cpl_table *points, cpl_table *evaluate,
14949 int samples, int order)
14950 {
14951
14952 const char *func = "mos_montecarlo_polyfit";
14953
14954 cpl_polynomial *p;
14955 cpl_polynomial *q;
14956 cpl_vector *listx;
14957 cpl_vector *listy;
14958 double err;
14959 double *x;
14960 double *px;
14961 double *x_eval;
14962 double *px_eval;
14963 double *sigma;
14964 double *vy;
14965 double *dy;
14966 int npoints, nevaluate;
14967 int i, j;
14968
14969
14970 if (points == NULL || evaluate == NULL) {
14971 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14972 return NULL;
14973 }
14974
14975 if (!cpl_table_has_column(points, "x")) {
14976 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14977 return NULL;
14978 }
14979
14980 if (cpl_table_get_column_type(points, "x") != CPL_TYPE_DOUBLE) {
14981 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
14982 return NULL;
14983 }
14984
14985 if (cpl_table_has_invalid(points, "x")) {
14986 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14987 return NULL;
14988 }
14989
14990 if (!cpl_table_has_column(points, "y")) {
14991 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14992 return NULL;
14993 }
14994
14995 if (cpl_table_get_column_type(points, "y") != CPL_TYPE_DOUBLE) {
14996 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
14997 return NULL;
14998 }
14999
15000 if (cpl_table_has_invalid(points, "y")) {
15001 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15002 return NULL;
15003 }
15004
15005 if (cpl_table_has_column(points, "y_err")) {
15006
15007 if (cpl_table_get_column_type(points, "y_err") != CPL_TYPE_DOUBLE) {
15008 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15009 return NULL;
15010 }
15011
15012 if (cpl_table_has_invalid(points, "y_err")) {
15013 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15014 return NULL;
15015 }
15016 }
15017
15018 if (!cpl_table_has_column(evaluate, "x")) {
15019 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15020 return NULL;
15021 }
15022
15023 if (cpl_table_get_column_type(evaluate, "x") != CPL_TYPE_DOUBLE) {
15024 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15025 return NULL;
15026 }
15027
15028 if (cpl_table_has_invalid(evaluate, "x")) {
15029 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15030 return NULL;
15031 }
15032
15033 if (samples < 2 || order < 0) {
15034 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15035 return NULL;
15036 }
15037
15038 npoints = cpl_table_get_nrow(points);
15039 listx = cpl_vector_wrap(npoints, cpl_table_get_data_double(points, "x"));
15040 listy = cpl_vector_wrap(npoints, cpl_table_get_data_double(points, "y"));
15041
15042 p = cpl_polynomial_fit_1d_create(listx, listy, order, &err);
15043
15044 if (!cpl_table_has_column(points, "y_err")) {
15045 err = sqrt(err);
15046 cpl_table_new_column(points, "y_err", CPL_TYPE_DOUBLE);
15047 cpl_table_fill_column_window_double(points, "y_err", 0, npoints, err);
15048 cpl_msg_info(func, "Error column not found - set to %f\n", err);
15049 }
15050
15051
15052
15053
15054
15055 if (cpl_table_has_column(points, "px"))
15056 cpl_table_erase_column(points, "px");
15057 cpl_table_new_column(points, "px", CPL_TYPE_DOUBLE);
15058 cpl_table_fill_column_window_double(points, "px", 0, npoints, 0);
15059 x = cpl_table_get_data_double(points, "x");
15060 px = cpl_table_get_data_double(points, "px");
15061 for (i = 0; i < npoints; i++)
15062 px[i] = cpl_polynomial_eval_1d(p, x[i], NULL);
15063
15064 nevaluate = cpl_table_get_nrow(evaluate);
15065
15066 if (cpl_table_has_column(evaluate, "px"))
15067 cpl_table_erase_column(evaluate, "px");
15068 cpl_table_new_column(evaluate, "px", CPL_TYPE_DOUBLE);
15069 cpl_table_fill_column_window_double(evaluate, "px", 0, nevaluate, 0);
15070 x_eval = cpl_table_get_data_double(evaluate, "x");
15071 px_eval = cpl_table_get_data_double(evaluate, "px");
15072 for (i = 0; i < nevaluate; i++)
15073 px_eval[i] = cpl_polynomial_eval_1d(p, x_eval[i], NULL);
15074
15075
15076
15077
15078
15079 if (cpl_table_has_column(evaluate, "sigma"))
15080 cpl_table_erase_column(evaluate, "sigma");
15081 cpl_table_new_column(evaluate, "sigma", CPL_TYPE_DOUBLE);
15082 cpl_table_fill_column_window_double(evaluate, "sigma", 0, nevaluate, 0);
15083 sigma = cpl_table_get_data_double(evaluate, "sigma");
15084
15085
15086
15087
15088
15089 if (cpl_table_has_column(points, "vy"))
15090 cpl_table_erase_column(points, "vy");
15091 cpl_table_new_column(points, "vy", CPL_TYPE_DOUBLE);
15092 cpl_table_fill_column_window_double(points, "vy", 0, npoints, 0);
15093 vy = cpl_table_get_data_double(points, "vy");
15094 dy = cpl_table_get_data_double(points, "y_err");
15095 cpl_vector_unwrap(listy);
15096 listy = cpl_vector_wrap(npoints, vy);
15097
15098 for (i = 0; i < samples; i++) {
15099 for (j = 0; j < npoints; j++)
15100 vy[j] = px[j] + dy[j] * mos_randg(1);
15101 q = cpl_polynomial_fit_1d_create(listx, listy, order, NULL);
15102 for (j = 0; j < nevaluate; j++)
15103 sigma[j] += fabs(px_eval[j]
15104 - cpl_polynomial_eval_1d(q, x_eval[j], NULL));
15105 cpl_polynomial_delete(q);
15106 }
15107
15108
15109
15110
15111
15112 cpl_table_multiply_scalar(evaluate, "sigma", 1.25);
15113 cpl_table_divide_scalar(evaluate, "sigma", samples);
15114
15115 cpl_vector_unwrap(listx);
15116 cpl_vector_unwrap(listy);
15117
15118 return p;
15119 }
15120
15121 #endif
15122
15132 cpl_error_code mos_refmask_find_gaps(cpl_mask * refmask,
15133 cpl_image * master_flat)
15134 {
15135 int nx = cpl_mask_get_size_x(refmask);
15136 int ny = cpl_mask_get_size_y(refmask);
15137
15138 int * xpos = cpl_calloc(sizeof(int), ny);
15139
15140 cpl_vector * v = cpl_vector_new(ny);
15141 cpl_vector * truev;
15142 int nvalid = 0;
15143 double * flats = cpl_vector_get_data(v);
15144
15145 double median, stdev;
15146
15147 int i;
15148
15149
15150 for (i = 1; i <= ny; i++) {
15151 int j = 0;
15152
15153 do j++;
15154 while (!cpl_mask_get(refmask, j, i) && j < nx);
15155
15156 if (j < nx) {
15157 int rejected;
15158
15159 xpos[i - 1] = j;
15160 flats[nvalid] = cpl_image_get(master_flat, j, i, &rejected);
15161 nvalid++;
15162 }
15163 else {
15164 xpos[i - 1] = -1;
15165 }
15166 }
15167
15168 truev = cpl_vector_wrap(nvalid, flats);
15169
15170 median = cpl_vector_get_median(truev);
15171 stdev = cpl_vector_get_stdev(truev);
15172
15173 cpl_vector_unwrap(truev);
15174 cpl_vector_delete(v);
15175
15176 for (i = 1; i <= ny; i++) {
15177 if (xpos[i - 1] > 0) {
15178 int rejected;
15179 double kappa = 1.0;
15180 double delta =
15181 cpl_image_get(master_flat, xpos[i - 1], i, &rejected) - median;
15182
15183 if (fabs(delta) > stdev * kappa) {
15184 int j = 0;
15185
15186 while (cpl_mask_get(refmask, xpos[i - 1] + j, i)) {
15187 cpl_mask_set(refmask, xpos[i - 1] + j, i, CPL_BINARY_0);
15188 j++;
15189 }
15190 }
15191 }
15192 }
15193
15194 cpl_free(xpos);
15195
15196 return cpl_error_get_code();
15197 }
15198
15206 cpl_error_code mos_saturation_process(cpl_image * image)
15207 {
15208 int nx = cpl_image_get_size_x(image);
15209 int ny = cpl_image_get_size_y(image);
15210 int npix = nx * ny;
15211 float * sdata = cpl_image_get_data_float(image);
15212
15213 int count, i, j, k;
15214
15215
15216
15217
15218
15219
15220
15221 for (i = 0; i < npix - nx; i++)
15222 if (sdata[i] == 0.0 && sdata[i + nx] == 0.0)
15223 sdata[i] = 65535.0;
15224
15225 for (i = npix - nx; i < npix; i++)
15226 if (sdata[i] == 0.0)
15227 sdata[i] = 65535.0;
15228
15229
15230
15231
15232
15233
15234
15235 for (i = 0; i < npix; i++) {
15236 if (sdata[i] >= 65535.0) {
15237 count = 0;
15238 for (j = i; j < npix; j++) {
15239 if (sdata[j] < 65535.0) {
15240 break;
15241 }
15242 else {
15243 count++;
15244 }
15245 }
15246 if (count < 30 && count > 2) {
15247 for (j = i; j < i + count/2; j++)
15248 sdata[j] = sdata[i] + 1000.0 * (j - i);
15249 if (count % 2 != 0) {
15250 sdata[j] = sdata[j-1] + 1000.0;
15251 j++;
15252 }
15253 for (k = j; k <= i + count; k++)
15254 sdata[k] = sdata[i] - 1000.0 * (k - i - count);
15255 i = k;
15256 }
15257 }
15258 }
15259
15260 return cpl_error_get_code();
15261 }
15262
15270 cpl_error_code mos_subtract_background(cpl_image * image)
15271 {
15272
15273
15274
15275
15276 cpl_image * bimage = mos_arc_background(image, 15, 15);
15277 cpl_image_subtract(image, bimage);
15278 cpl_image_delete(bimage);
15279
15280 return cpl_error_get_code();
15281 }
15282
15297 cpl_error_code mos_object_intersect(cpl_table ** slitss,
15298 cpl_table * origslits, int nscience)
15299 {
15300 int i, j;
15301
15302 cpl_table *summary;
15303 int summary_nobjs = 0;
15304
15305 int nobjs;
15306
15307 int nmatches;
15308 int nslits = cpl_table_get_nrow(slitss[0]);
15309
15310 const float tolerance = 5.0;
15311
15312 int maxobjs;
15313 int k, m;
15314 int nstokes, sstokes;
15315
15316 cpl_table **work;
15317
15318 work = (cpl_table **)cpl_malloc(sizeof(cpl_table *) * nscience);
15319
15320
15321
15322
15323
15324
15325
15326
15327
15328
15329 for (j = 0; j < nscience; j++) {
15330 int c_nobjs = mos_get_nobjects(slitss[j]);
15331 if (!c_nobjs)
15332 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
15333 summary_nobjs += c_nobjs;
15334 }
15335
15336 summary = cpl_table_new(summary_nobjs);
15337
15338 cpl_table_new_column(summary, "offset", CPL_TYPE_DOUBLE);
15339 cpl_table_new_column(summary, "pair", CPL_TYPE_INT);
15340
15341
15342
15343
15344
15345 nobjs = 0;
15346
15347
15348 for (j = 0; j < nscience; j++) {
15349 int c_maxobjs = mos_get_maxobjs_per_slit(slitss[j]);
15350
15351
15352 for (k = 0; k < nslits; k++) {
15353
15354
15355 for (m = 0; m < c_maxobjs; m++) {
15356 int null;
15357 char *name = cpl_sprintf("object_%d", m + 1);
15358 double obj = cpl_table_get_double(slitss[j], name, k, &null);
15359 int pos;
15360 int pair;
15361
15362 cpl_free(name);
15363
15364 if (null)
15365 break;
15366
15367
15368
15369
15370
15371
15372
15373
15374 pos = cpl_table_get_int(slitss[j], "position", k, &null);
15375 pair = cpl_table_get_int(slitss[j], "pair_id", k, &null);
15376 cpl_table_set(summary, "offset", nobjs, obj - pos);
15377 cpl_table_set(summary, "pair", nobjs, pair);
15378
15379 nobjs++;
15380 }
15381 }
15382 }
15383
15384
15385
15386
15387
15388
15389
15390
15391
15392
15393 nmatches = 0;
15394 maxobjs = mos_get_maxobjs_per_slit(slitss[0]);
15395
15396
15397
15398
15399
15400
15401
15402
15403
15404
15405
15406
15407 for (k = 0; k < nslits; k+=2) {
15408 int slitmatches = 0;
15409 for (m = 0; m < maxobjs; m++) {
15410 int null;
15411 char *name = cpl_sprintf("object_%d", m + 1);
15412 double obj = cpl_table_get_double(slitss[0], name, k, &null);
15413 double pos;
15414 int pair;
15415
15416 char *name_obj;
15417 char *name_start;
15418 char *name_end;
15419 char *name_row;
15420 char *name_row_s;
15421
15422 char *name_start_o;
15423 char *name_end_o;
15424 char *name_row_o;
15425
15426 int start, end;
15427 int length;
15428
15429 int selected;
15430
15431
15432 cpl_free(name);
15433
15434 if (null)
15435 break;
15436
15437
15438
15439
15440
15441
15442
15443
15444 pos = cpl_table_get_int(slitss[0], "position", k, &null);
15445 pair = cpl_table_get_int(slitss[0], "pair_id", k, &null);
15446
15447
15448
15449
15450
15451
15452
15453
15454
15455 cpl_table_select_all(summary);
15456
15457 cpl_table_and_selected_int(summary, "pair", CPL_EQUAL_TO, pair);
15458 cpl_table_and_selected_double(summary, "offset", CPL_LESS_THAN,
15459 obj - pos + tolerance);
15460 selected =
15461 cpl_table_and_selected_double(summary, "offset", CPL_GREATER_THAN,
15462 obj - pos - tolerance);
15463
15464
15465
15466
15467
15468
15469
15470
15471 if (selected != nscience * 2)
15472 continue;
15473
15474
15475
15476
15477
15478
15479
15480 slitmatches++;
15481
15482
15483
15484
15485
15486
15487
15488
15489
15490
15491
15492 name_obj = cpl_sprintf("object_%d", slitmatches);
15493 name_start = cpl_sprintf("start_%d", slitmatches);
15494 name_end = cpl_sprintf("end_%d", slitmatches);
15495 name_row = cpl_sprintf("row_%d", slitmatches);
15496 name_row_s = cpl_sprintf("row_stokes_%d", slitmatches);
15497
15498
15499
15500
15501
15502
15503 name_start_o = cpl_sprintf("start_%d", m + 1);
15504 name_end_o = cpl_sprintf("end_%d", m + 1);
15505 name_row_o = cpl_sprintf("row_%d", m + 1);
15506
15507
15508
15509
15510
15511 if (!cpl_table_has_column(origslits, name_obj)) {
15512 cpl_table_new_column(origslits, name_obj, CPL_TYPE_DOUBLE);
15513 cpl_table_new_column(origslits, name_start, CPL_TYPE_INT);
15514 cpl_table_new_column(origslits, name_end, CPL_TYPE_INT);
15515 cpl_table_new_column(origslits, name_row, CPL_TYPE_INT);
15516 cpl_table_new_column(origslits, name_row_s, CPL_TYPE_INT);
15517 }
15518
15519
15520
15521
15522
15523
15524
15525
15526 length = cpl_table_get_int(origslits, "length", k + 1, &null);
15527
15528
15529
15530
15531
15532
15533 start = cpl_table_get_int(slitss[0], name_start_o, k, &null);
15534 end = cpl_table_get_int(slitss[0], name_end_o, k, &null);
15535
15536
15537
15538
15539
15540
15541
15542
15543
15544
15545 cpl_table_set_double(origslits, name_obj, k, obj);
15546 cpl_table_set_double(origslits, name_obj, k + 1, obj - length);
15547
15548 cpl_table_set_int(origslits, name_start, k, start);
15549 cpl_table_set_int(origslits, name_start, k + 1, start - length);
15550
15551 cpl_table_set_int(origslits, name_end, k, end);
15552 cpl_table_set_int(origslits, name_end, k + 1, end - length);
15553
15554
15555
15556
15557
15558
15559
15560
15561
15562
15563
15564
15565
15566 cpl_table_set_int(origslits, name_row, k, nmatches);
15567 nmatches++;
15568 cpl_table_set_int(origslits, name_row, k + 1, nmatches);
15569 nmatches++;
15570
15571 cpl_free(name_obj);
15572 cpl_free(name_start);
15573 cpl_free(name_end);
15574 cpl_free(name_row);
15575 cpl_free(name_row_s);
15576
15577 cpl_free(name_start_o);
15578 cpl_free(name_end_o);
15579 cpl_free(name_row_o);
15580 }
15581 }
15582
15583
15584
15585
15586
15587
15588 cpl_table_delete(summary);
15589
15590 if (!nmatches)
15591 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
15592
15593
15594
15595
15596
15597
15598
15599
15600
15601
15602
15603 maxobjs = mos_get_maxobjs_per_slit(origslits);
15604 nstokes = nmatches / 2;
15605
15606 for (k = 0; k < nslits; k++) {
15607 if (k % 2) {
15608 nstokes = sstokes;
15609 }
15610 else {
15611 sstokes = nstokes;
15612 }
15613
15614 for (m = 0; m < maxobjs; m++) {
15615 char *name = cpl_sprintf("row_%d", m + 1);
15616 char *namestokes = cpl_sprintf("row_stokes_%d", m + 1);
15617
15618 if (!cpl_table_is_valid(origslits, name, k)) {
15619 cpl_free(name);
15620 cpl_free(namestokes);
15621 break;
15622 }
15623 else {
15624 nmatches--;
15625 nstokes--;
15626 cpl_table_set_int(origslits, name, k, nmatches);
15627 cpl_table_set_int(origslits, namestokes, k, nstokes);
15628 }
15629
15630 cpl_free(name);
15631 cpl_free(namestokes);
15632 }
15633 }
15634
15635
15636
15637
15638
15639
15640
15641
15642
15643 for (j = 0; j < maxobjs; j++) {
15644 char *name = cpl_sprintf("object_%d", j + 1);
15645 cpl_table_fill_invalid_double(origslits, name, -1);
15646 cpl_free(name);
15647
15648 name = cpl_sprintf("start_%d", j + 1);
15649 cpl_table_fill_invalid_int(origslits, name, -1);
15650 cpl_free(name);
15651
15652 name = cpl_sprintf("end_%d", j + 1);
15653 cpl_table_fill_invalid_int(origslits, name, -1);
15654 cpl_free(name);
15655
15656 name = cpl_sprintf("row_%d", j + 1);
15657 cpl_table_fill_invalid_int(origslits, name, -1);
15658 cpl_free(name);
15659
15660 name = cpl_sprintf("row_stokes_%d", j + 1);
15661 cpl_table_fill_invalid_int(origslits, name, -1);
15662 cpl_free(name);
15663 }
15664
15665
15666
15667
15668
15669
15670
15671
15672
15673
15674
15675
15676 for (i = 0; i < nscience; i++) {
15677 int c_maxobjs = mos_get_maxobjs_per_slit(slitss[i]);
15678
15679 work[i] = cpl_table_duplicate(slitss[i]);
15680
15681 for (m = 0; m < c_maxobjs; m++) {
15682 char *object_o = cpl_sprintf("object_%d", m + 1);
15683 char *start_o = cpl_sprintf("start_%d", m + 1);
15684 char *end_o = cpl_sprintf("end_%d", m + 1);
15685 char *row_o = cpl_sprintf("row_%d", m + 1);
15686
15687 cpl_table_erase_column(slitss[i], object_o);
15688 cpl_table_erase_column(slitss[i], start_o);
15689 cpl_table_erase_column(slitss[i], end_o);
15690 cpl_table_erase_column(slitss[i], row_o);
15691 }
15692 }
15693
15694
15695
15696
15697
15698 for (k = 0; k < nslits; k++) {
15699 for (j = 0; j < maxobjs; j++) {
15700 double object_w, object_r;
15701 int start_w, start_r;
15702 int end_w, end_r;
15703 int row_w, row_r;
15704
15705 char *object_i = cpl_sprintf("object_%d", j + 1);
15706 char *start_i = cpl_sprintf("start_%d", j + 1);
15707 char *end_i = cpl_sprintf("end_%d", j + 1);
15708 char *row_i = cpl_sprintf("row_%d", j + 1);
15709
15710
15711 if (!cpl_table_is_valid(origslits, object_i, k))
15712 break;
15713
15714
15715
15716
15717
15718
15719
15720
15721
15722
15723
15724 object_w = cpl_table_get_double(origslits, object_i, k, NULL);
15725 start_w = cpl_table_get_int (origslits, start_i, k, NULL);
15726 end_w = cpl_table_get_int (origslits, end_i, k, NULL);
15727 row_w = cpl_table_get_int (origslits, row_i, k, NULL);
15728
15729 for (i = 0; i < nscience; i++) {
15730 int c_maxobjs = mos_get_maxobjs_per_slit(work[i]);
15731 int minpos;
15732 double mindiff, diff;
15733 char *object_o;
15734 char *start_o;
15735 char *end_o;
15736 char *row_o;
15737
15738 for (m = 0; m < c_maxobjs; m++) {
15739 object_o = cpl_sprintf("object_%d", m + 1);
15740 start_o = cpl_sprintf("start_%d", m + 1);
15741 end_o = cpl_sprintf("end_%d", m + 1);
15742 row_o = cpl_sprintf("row_%d", m + 1);
15743
15744 if (!cpl_table_is_valid(work[i], object_o, k))
15745 break;
15746
15747 object_r = cpl_table_get_double(work[i], object_o, k, NULL);
15748 start_r = cpl_table_get_int (work[i], start_o, k, NULL);
15749 end_r = cpl_table_get_int (work[i], end_o, k, NULL);
15750 row_r = cpl_table_get_int (work[i], row_o, k, NULL);
15751
15752 diff = fabs(object_w - object_r);
15753 if (m) {
15754 if (mindiff > diff) {
15755 mindiff = diff;
15756 minpos = m;
15757 }
15758 }
15759 else {
15760 mindiff = diff;
15761 minpos = 0;
15762 }
15763
15764 cpl_free(object_o);
15765 cpl_free(start_o);
15766 cpl_free(end_o);
15767 cpl_free(row_o);
15768 }
15769
15770 object_o = cpl_sprintf("object_%d", minpos + 1);
15771 start_o = cpl_sprintf("start_%d", minpos + 1);
15772 end_o = cpl_sprintf("end_%d", minpos + 1);
15773 row_o = cpl_sprintf("row_%d", minpos + 1);
15774
15775 if (!cpl_table_has_column(slitss[i], object_i)) {
15776 cpl_table_new_column(slitss[i], object_i, CPL_TYPE_DOUBLE);
15777 cpl_table_new_column(slitss[i], start_i, CPL_TYPE_INT);
15778 cpl_table_new_column(slitss[i], end_i, CPL_TYPE_INT);
15779 cpl_table_new_column(slitss[i], row_i, CPL_TYPE_INT);
15780 cpl_table_fill_invalid_double(slitss[i], object_i, -1);
15781 cpl_table_fill_invalid_int (slitss[i], start_i, -1);
15782 cpl_table_fill_invalid_int (slitss[i], end_i, -1);
15783 cpl_table_fill_invalid_int (slitss[i], row_i, -1);
15784 }
15785
15786 cpl_table_set_double(slitss[i], object_i, k,
15787 cpl_table_get_double(work[i], object_o,
15788 k, NULL));
15789 cpl_table_set_int(slitss[i], start_i , k,
15790 cpl_table_get_int(work[i], start_o, k, NULL));
15791 cpl_table_set_int(slitss[i], end_i , k,
15792 cpl_table_get_int(work[i], end_o, k, NULL));
15793 cpl_table_set_int(slitss[i], row_i , k, row_w);
15794
15795 cpl_free(object_o);
15796 cpl_free(start_o);
15797 cpl_free(end_o);
15798 cpl_free(row_o);
15799 }
15800
15801 cpl_free(object_i);
15802 cpl_free(start_i);
15803 cpl_free(end_i);
15804 cpl_free(row_i);
15805 }
15806 }
15807
15808 for (i = 0; i < nscience; i++)
15809 cpl_table_delete(work[i]);
15810
15811 cpl_free(work);
15812
15813
15814 return cpl_error_get_code();
15815 }
15816
15817
15825 int mos_get_maxobjs_per_slit(cpl_table * slits)
15826 {
15827 int maxobjs = 1;
15828
15829 char * colname = cpl_sprintf("object_%d", maxobjs);
15830
15831 while (cpl_table_has_column(slits, colname)) {
15832 maxobjs++;
15833 cpl_free(colname);
15834 colname = cpl_sprintf("object_%d", maxobjs);
15835 }
15836
15837 cpl_free(colname);
15838
15839 maxobjs--;
15840
15841 return maxobjs;
15842 }
15843
15851 int mos_get_nobjects(cpl_table * slits)
15852 {
15853 int nobjs = 0;
15854
15855 int nslits = cpl_table_get_nrow(slits);
15856 int maxobjs = mos_get_maxobjs_per_slit(slits);
15857
15858 int k, m;
15859
15860 for (k = 0; k < nslits; k++) {
15861 for (m = 0; m < maxobjs; m++) {
15862 char * name = cpl_sprintf("object_%d", m + 1);
15863 int null = !cpl_table_is_valid(slits, name, k);
15864
15865 cpl_free(name);
15866
15867 if (null) break;
15868 else nobjs++;
15869 }
15870 }
15871
15872 return nobjs;
15873 }
15874
15882 int mos_check_slits(cpl_table * slits)
15883 {
15884
15885 cpl_propertylist * sort;
15886
15887 int nslits = cpl_table_get_nrow(slits);
15888
15889 int k, null;
15890
15891
15892 for (k = 0; k < nslits; k++) {
15893 double ytop = cpl_table_get_double(slits, "ytop", k, &null);
15894 double ybottom = cpl_table_get_double(slits, "ybottom", k, &null);
15895
15896 double xtop = cpl_table_get_double(slits, "xtop", k, &null);
15897 double xbottom = cpl_table_get_double(slits, "xbottom", k, &null);
15898
15899 int nmiss = (int)((ytop - ybottom) / 90.0 + 0.5);
15900
15901 if (nmiss > 1) {
15902 cpl_msg_warning(cpl_func,
15903 "Some slits could not be properly detected. "
15904 "There might be accountable inaccuracies.");
15905 while (nmiss > 1) {
15906 cpl_table_set_size(slits, nslits + 1);
15907
15908
15909
15910
15911 cpl_table_set_double(slits, "xtop", nslits, xtop);
15912 cpl_table_set_double(slits, "xbottom", nslits, xbottom);
15913
15914
15915 if (k == 0) {
15916 cpl_table_set_double(slits, "ybottom", nslits, ybottom);
15917 cpl_table_set_double(slits, "ytop", nslits, ybottom
15918 + 85.0);
15919 ybottom += 90.0;
15920 cpl_table_set_double(slits, "ybottom", k, ybottom);
15921 } else {
15922 cpl_table_set_double(slits, "ytop", nslits, ytop);
15923 cpl_table_set_double(slits, "ybottom", nslits, ytop
15924 - 85.0);
15925 ytop -= 90.0;
15926 cpl_table_set_double(slits, "ytop", k, ytop);
15927 }
15928
15929 nslits++; nmiss--;
15930 }
15931 }
15932 }
15933
15934 sort = cpl_propertylist_new();
15935 cpl_propertylist_append_bool(sort, "ytop", 1);
15936 cpl_table_sort(slits, sort);
15937 cpl_propertylist_delete(sort);
15938
15939 return 0;
15940 }
15941
15964 cpl_table *mos_load_slits_fors_pmos(cpl_propertylist *header)
15965 {
15966 int m, null;
15967 int halfsize;
15968
15969 cpl_propertylist * sort;
15970 cpl_table * slits;
15971
15972 slits = mos_load_slits_fors_mos(header);
15973 halfsize = cpl_table_get_nrow(slits);
15974
15975 cpl_table_set_size(slits, 2 * halfsize);
15976
15977 for (m = 0; m < halfsize; m++) {
15978
15979 double gap = 1.4;
15980
15981 double length =
15982 cpl_table_get(slits, "ytop", m, &null) -
15983 cpl_table_get(slits, "ybottom", m, &null);
15984
15985 if (m) {
15986 double interval =
15987 cpl_table_get(slits, "ybottom", m - 1, &null) -
15988 cpl_table_get(slits, "ytop", m, &null);
15989
15990 gap = (interval - length) / 2;
15991 }
15992
15993 cpl_table_set(slits, "slit_id", m + halfsize,
15994 cpl_table_get(slits, "slit_id", m, &null) - 1);
15995
15996 cpl_table_set(slits, "xtop", m + halfsize,
15997 cpl_table_get(slits, "xtop", m, &null));
15998
15999 cpl_table_set(slits, "xbottom", m + halfsize,
16000 cpl_table_get(slits, "xbottom", m, &null));
16001
16002 cpl_table_set(slits, "ytop", m + halfsize,
16003 cpl_table_get(slits, "ytop", m, &null) + gap + length);
16004
16005 cpl_table_set(slits, "ybottom", m + halfsize,
16006 cpl_table_get(slits, "ytop", m, &null) + gap);
16007 }
16008
16009 for (m = 0; m < 2 * halfsize; m++) {
16010 cpl_table_set(slits, "ytop", m,
16011 cpl_table_get(slits, "ytop", m, &null) - 5.3);
16012
16013 cpl_table_set(slits, "ybottom", m,
16014 cpl_table_get(slits, "ybottom", m, &null) - 5.3);
16015
16016 }
16017
16018 sort = cpl_propertylist_new();
16019 cpl_propertylist_append_bool(sort, "ytop", 1);
16020 cpl_table_sort(slits, sort);
16021
16022 cpl_propertylist_delete(sort);
16023
16024 return slits;
16025 }
16026
16027 int * fors_get_nobjs_perslit(cpl_table * slits)
16028 {
16029 int nslits = cpl_table_get_nrow(slits);
16030 int maxobjs = mos_get_maxobjs_per_slit(slits);
16031
16032 int * nobjs_per_slit = cpl_malloc(sizeof(int) * nslits);
16033
16034 int k, m;
16035
16036 for (k = 0; k < nslits; k++) {
16037 int nobjs = 0;
16038 for (m = 0; m < maxobjs; m++) {
16039 char * name = cpl_sprintf("object_%d", m + 1);
16040 int null = !cpl_table_is_valid(slits, name, k);
16041
16042 cpl_free(name);
16043
16044 if (null) break;
16045 else nobjs++;
16046 }
16047
16048 nobjs_per_slit[k] = nobjs;
16049 }
16050
16051 return nobjs_per_slit;
16052 }