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, int multiplex)
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, valid;
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 if (multiplex >= 0) {
04245
04246
04247
04248
04249
04250
04251 if (max > 5) {
04252 valid = -1;
04253 for (i = 0; i < nseq; i++) {
04254 if (seq_length[i] > 5) {
04255 valid++;
04256 }
04257 if (multiplex == valid) {
04258 max = seq_length[i];
04259 maxpos = i;
04260 break;
04261 }
04262 }
04263 }
04264 }
04265
04266
04267
04268
04269
04270
04271 nn = 0;
04272 for (i = 0; i < maxpos; i++)
04273 nn += seq_length[i];
04274
04275
04276
04277
04278
04279 n = max;
04280 for (i = 0; i < n; i++, nn++) {
04281 xpos[i] = xpos[nn];
04282 lambda[i] = lambda[nn];
04283 ilambda[i] = ilambda[nn];
04284 }
04285
04286
04287
04288
04289
04290
04291 for (i = 1; i < n; i++) {
04292 gap = ilambda[i] - ilambda[i-1];
04293 for (j = 1; j < gap; j++) {
04294
04295 if (j == 1) {
04296
04297
04298
04299
04300
04301 disp = (lambda[i] - lambda[i-1]) / (xpos[i] - xpos[i-1]);
04302 }
04303
04304
04305
04306
04307
04308
04309 hi_start = xpos[i-1] + (line[ilambda[i-1] + j] - lambda[i-1]) / disp;
04310
04311
04312
04313
04314
04315
04316
04317
04318
04319
04320
04321
04322
04323 found = 0;
04324 for (k = 0; k < npeaks; k++) {
04325 if (fabs(peak[k] - hi_start) < 2) {
04326 for (l = n; l > i; l--) {
04327 xpos[l] = xpos[l-1];
04328 lambda[l] = lambda[l-1];
04329 ilambda[l] = ilambda[l-1];
04330 }
04331 xpos[i] = peak[k];
04332 lambda[i] = line[ilambda[i-1] + j];
04333 ilambda[i] = ilambda[i-1] + j;
04334 ++n;
04335 found = 1;
04336 break;
04337 }
04338 }
04339 if (found)
04340 break;
04341 }
04342 }
04343
04344
04345
04346
04347
04348
04349 found = 1;
04350 while (ilambda[n-1] < nlines - 1 && found) {
04351
04352
04353
04354
04355
04356
04357 if (n > 1)
04358 disp = (lambda[n-1] - lambda[n-2]) / (xpos[n-1] - xpos[n-2]);
04359 else
04360 disp = 0.0;
04361
04362 if (disp > max_disp || disp < min_disp)
04363 break;
04364
04365
04366
04367
04368
04369
04370
04371 hi_start = xpos[n-1] + (line[ilambda[n-1] + 1] - lambda[n-1]) / disp;
04372
04373
04374
04375
04376
04377
04378
04379
04380
04381 found = 0;
04382 min = fabs(peak[0] - hi_start);
04383 minpos = 0;
04384 for (k = 1; k < npeaks; k++) {
04385 if (min > fabs(peak[k] - hi_start)) {
04386 min = fabs(peak[k] - hi_start);
04387 minpos = k;
04388 }
04389 }
04390 if (min < 6 && fabs(peak[minpos] - xpos[n-1]) > 1.0) {
04391 xpos[n] = peak[minpos];
04392 lambda[n] = line[ilambda[n-1] + 1];
04393 ilambda[n] = ilambda[n-1] + 1;
04394 ++n;
04395 found = 1;
04396 }
04397 }
04398
04399
04400
04401
04402
04403
04404 found = 1;
04405 while (ilambda[0] > 0 && found) {
04406
04407
04408
04409
04410
04411
04412 disp = (lambda[1] - lambda[0]) / (xpos[1] - xpos[0]);
04413
04414 if (disp > max_disp || disp < min_disp)
04415 break;
04416
04417
04418
04419
04420
04421
04422
04423 hi_start = xpos[0] - (lambda[0] - line[ilambda[0] - 1]) / disp;
04424
04425
04426
04427
04428
04429
04430
04431
04432
04433
04434 found = 0;
04435 min = fabs(peak[0] - hi_start);
04436 minpos = 0;
04437 for (k = 1; k < npeaks; k++) {
04438 if (min > fabs(peak[k] - hi_start)) {
04439 min = fabs(peak[k] - hi_start);
04440 minpos = k;
04441 }
04442 }
04443 if (min < 6 && fabs(peak[minpos] - xpos[0]) > 1.0) {
04444 for (j = n; j > 0; j--) {
04445 xpos[j] = xpos[j-1];
04446 lambda[j] = lambda[j-1];
04447 ilambda[j] = ilambda[j-1];
04448 }
04449 xpos[0] = peak[minpos];
04450 lambda[0] = line[ilambda[0] - 1];
04451 ilambda[0] = ilambda[0] - 1;
04452 ++n;
04453 found = 1;
04454 }
04455 }
04456 }
04457
04458
04459
04460
04461
04462
04463
04464
04465
04466
04467
04468
04469
04470
04471
04472
04473
04474
04475
04476
04477 for (i = 0; i < npeaks; i++)
04478 cpl_free(ident[i]);
04479 cpl_free(ident);
04480 cpl_free(nident);
04481 cpl_free(lident);
04482 cpl_free(ilambda);
04483 cpl_free(tmp_xpos);
04484 cpl_free(tmp_lambda);
04485 cpl_free(tmp_ilambda);
04486 cpl_free(peak_lo);
04487 cpl_free(flag);
04488 cpl_free(seq_length);
04489 cpl_free(peak_hi);
04490
04491 if (n == 0) {
04492 cpl_free(xpos);
04493 cpl_free(lambda);
04494 return NULL;
04495 }
04496
04497 return cpl_bivector_wrap_vectors(cpl_vector_wrap(n, xpos),
04498 cpl_vector_wrap(n, lambda));
04499 }
04500
04501
04519
04520
04521
04522
04523
04524
04525
04526
04527
04528
04529
04530
04531
04532
04533
04534
04535
04536
04537
04538
04539
04540
04541
04542
04543
04544
04545
04546
04547
04548
04549
04550
04551
04552
04553
04554
04555
04556
04557
04558
04559 double mos_eval_dds(cpl_polynomial *ids, double blue, double red,
04560 double refwave, double pixel)
04561 {
04562 double yellow;
04563 double coeff;
04564 int zero = 0;
04565
04566 if (cpl_polynomial_eval_1d(ids, blue-refwave, NULL) > pixel)
04567 return 0.0;
04568
04569 if (cpl_polynomial_eval_1d(ids, red-refwave, NULL) < pixel)
04570 return 0.0;
04571
04572 yellow = (blue + red) / 2 - refwave;
04573
04574 coeff = cpl_polynomial_get_coeff(ids, &zero);
04575 cpl_polynomial_set_coeff(ids, &zero, coeff - pixel);
04576
04577 cpl_polynomial_solve_1d(ids, yellow, &yellow, 1);
04578
04579 cpl_polynomial_set_coeff(ids, &zero, coeff);
04580
04581 return yellow + refwave;
04582
04583 }
04584
04610 cpl_polynomial *mos_poly_wav2pix(cpl_bivector *pixwav, int order,
04611 double reject, int minlines,
04612 int *nlines, double *err)
04613 {
04614 const char *func = "mos_poly_wav2pix";
04615
04616 cpl_bivector *pixwav2;
04617 cpl_vector *wavel;
04618 cpl_vector *pixel;
04619 double *d_wavel;
04620 double *d_pixel;
04621 double pixpos;
04622 int fitlines;
04623 int rejection = 0;
04624 int i, j;
04625
04626 cpl_polynomial *ids;
04627
04628
04629 *nlines = 0;
04630 *err = 0;
04631
04632 if (pixwav == NULL) {
04633 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
04634 return NULL;
04635 }
04636
04637 fitlines = cpl_bivector_get_size(pixwav);
04638
04639 if (fitlines < minlines) {
04640 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
04641 return NULL;
04642 }
04643
04644
04645
04646
04647
04648
04649
04650 if (reject > 0.0)
04651 rejection = 1;
04652
04653 if (rejection)
04654 pixwav2 = cpl_bivector_duplicate(pixwav);
04655 else
04656 pixwav2 = pixwav;
04657
04658
04659
04660
04661
04662
04663
04664 pixel = cpl_bivector_get_x(pixwav2);
04665 wavel = cpl_bivector_get_y(pixwav2);
04666
04667
04668
04669
04670
04671
04672 if (rejection)
04673 cpl_bivector_unwrap_vectors(pixwav2);
04674
04675
04676
04677
04678
04679
04680 while (fitlines >= minlines) {
04681
04682 ids = cpl_polynomial_fit_1d_create(wavel, pixel, order, err);
04683 *err = sqrt(*err);
04684
04685 if (ids == NULL) {
04686 cpl_msg_debug(cpl_error_get_where(), cpl_error_get_message());
04687 cpl_msg_debug(func, "Fitting IDS");
04688 cpl_error_set_where(func);
04689 if (rejection) {
04690 cpl_vector_delete(wavel);
04691 cpl_vector_delete(pixel);
04692 }
04693 return NULL;
04694 }
04695
04696 if (rejection) {
04697
04698
04699
04700
04701
04702
04703 d_pixel = cpl_vector_unwrap(pixel);
04704 d_wavel = cpl_vector_unwrap(wavel);
04705
04706 for (i = 0, j = 0; i < fitlines; i++) {
04707 pixpos = cpl_polynomial_eval_1d(ids, d_wavel[i], NULL);
04708 if (fabs(pixpos - d_pixel[i]) < reject) {
04709 d_pixel[j] = d_pixel[i];
04710 d_wavel[j] = d_wavel[i];
04711 j++;
04712 }
04713 }
04714
04715 if (j == fitlines) {
04716 cpl_free(d_wavel);
04717 cpl_free(d_pixel);
04718 *nlines = fitlines;
04719 return ids;
04720 }
04721 else {
04722 fitlines = j;
04723 cpl_polynomial_delete(ids);
04724 if (fitlines >= minlines) {
04725 pixel = cpl_vector_wrap(fitlines, d_pixel);
04726 wavel = cpl_vector_wrap(fitlines, d_wavel);
04727 }
04728 else {
04729 cpl_free(d_wavel);
04730 cpl_free(d_pixel);
04731 cpl_error_set(func, CPL_ERROR_CONTINUE);
04732 return NULL;
04733 }
04734 }
04735 }
04736 else {
04737 *nlines = fitlines;
04738 return ids;
04739 }
04740 }
04741
04742 return ids;
04743 }
04744
04745
04770 cpl_polynomial *mos_poly_pix2wav(cpl_bivector *pixwav, int order,
04771 double reject, int minlines,
04772 int *nlines, double *err)
04773 {
04774
04775 cpl_bivector *wavpix;
04776 cpl_vector *wavel;
04777 cpl_vector *pixel;
04778
04779 cpl_polynomial *dds;
04780
04781
04782
04783
04784
04785
04786 pixel = cpl_bivector_get_x(pixwav);
04787 wavel = cpl_bivector_get_y(pixwav);
04788
04789 wavpix = cpl_bivector_wrap_vectors(wavel, pixel);
04790
04791 dds = mos_poly_wav2pix(wavpix, order, reject, minlines, nlines, err);
04792
04793 cpl_bivector_unwrap_vectors(wavpix);
04794
04795 return dds;
04796
04797 }
04798
04799
04822 cpl_bivector *mos_find_peaks(const float *spectrum, int length, cpl_vector *lines,
04823 cpl_polynomial *ids, double refwave, int sradius)
04824 {
04825 const char *func = "mos_find_peaks";
04826
04827 double *data;
04828 double *d_pixel;
04829 double *d_wavel;
04830 float pos;
04831 int nlines;
04832 int pixel;
04833 int i, j;
04834
04835
04836 if (spectrum == NULL || lines == NULL || ids == NULL) {
04837 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
04838 return NULL;
04839 }
04840
04841 nlines = cpl_vector_get_size(lines);
04842
04843 if (sradius < 1 || length < 2*sradius+1 || nlines < 1) {
04844 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
04845 return NULL;
04846 }
04847
04848 d_wavel = cpl_malloc(nlines * sizeof(double));
04849 d_pixel = cpl_malloc(nlines * sizeof(double));
04850
04851 data = cpl_vector_get_data(lines);
04852
04853 for (i = 0, j = 0; i < nlines; i++) {
04854 pixel = cpl_polynomial_eval_1d(ids, data[i]-refwave, NULL) + 0.5;
04855 if (pixel - sradius < 0 || pixel + sradius >= length)
04856 continue;
04857 if (0 == peakPosition(spectrum+pixel-sradius, 2*sradius+1, &pos, 1)) {
04858 pos += pixel - sradius;
04859 d_pixel[j] = pos;
04860 d_wavel[j] = data[i];
04861 j++;
04862 }
04863 }
04864
04865 if (j > 0) {
04866 return cpl_bivector_wrap_vectors(cpl_vector_wrap(j, d_pixel),
04867 cpl_vector_wrap(j, d_wavel));
04868 }
04869 else {
04870 cpl_free(d_wavel);
04871 cpl_free(d_pixel);
04872 cpl_error_set(func, CPL_ERROR_ILLEGAL_OUTPUT);
04873 return NULL;
04874 }
04875 }
04876
04877
04995 cpl_image *mos_wavelength_calibration_raw(const cpl_image *image,
04996 cpl_vector *lines,
04997 double dispersion, float level,
04998 int sradius, int order,
04999 double reject, double refwave,
05000 double *wavestart, double *waveend,
05001 int *nlines, double *error,
05002 cpl_table *idscoeff,
05003 cpl_image *calibration,
05004 cpl_image *residuals,
05005 cpl_table *restable,
05006 cpl_mask *refmask)
05007 {
05008
05009 const char *func = "mos_wavelength_calibration_raw";
05010
05011 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
05012
05013
05014 double tolerance = 20.0;
05015 int step = 10;
05016
05017 char name[MAX_COLNAME];
05018 cpl_image *resampled;
05019 cpl_bivector *output;
05020 cpl_bivector *new_output;
05021 cpl_vector *peaks;
05022 cpl_vector *wavel;
05023 cpl_polynomial *ids;
05024 cpl_polynomial *lin;
05025 cpl_matrix *kernel;
05026 double ids_err;
05027 double max_disp, min_disp;
05028 double *line;
05029 double firstLambda, lastLambda, lambda;
05030 double value, wave, pixe;
05031 cpl_binary *mdata;
05032 const float *sdata;
05033 float *rdata;
05034 float *idata;
05035 float *ddata;
05036 float v1, v2, vi;
05037 float fpixel;
05038 int *have_it;
05039 int pixstart, pixend;
05040 int extrapolation;
05041 int nref;
05042 int nl, nx, ny, pixel;
05043 int countLines, usedLines;
05044 int uorder;
05045 int in, first, last;
05046 int width, uradius;
05047 int i, j, k;
05048
05049
05050 if (dispersion == 0.0) {
05051 cpl_msg_error(func, "The expected dispersion (A/pixel) must be given");
05052 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05053 return NULL;
05054 }
05055
05056 if (dispersion < 0.0) {
05057 cpl_msg_error(func, "The expected dispersion must be positive");
05058 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05059 return NULL;
05060 }
05061
05062 max_disp = dispersion + dispersion * tolerance / 100;
05063 min_disp = dispersion - dispersion * tolerance / 100;
05064
05065 if (order < 1) {
05066 cpl_msg_error(func, "The order of the fitting polynomial "
05067 "must be at least 1");
05068 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05069 return NULL;
05070 }
05071
05072 if (image == NULL || lines == NULL) {
05073 cpl_msg_error(func, "Both spectral exposure and reference line "
05074 "catalog are required in input");
05075 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05076 return NULL;
05077 }
05078
05079 nx = cpl_image_get_size_x(image);
05080 ny = cpl_image_get_size_y(image);
05081 sdata = cpl_image_get_data_float_const(image);
05082
05083 nref = cpl_vector_get_size(lines);
05084 line = cpl_vector_get_data(lines);
05085
05086 if (*wavestart < 1.0 && *waveend < 1.0) {
05087 firstLambda = line[0];
05088 lastLambda = line[nref-1];
05089 extrapolation = (lastLambda - firstLambda) / 10;
05090 firstLambda -= extrapolation;
05091 lastLambda += extrapolation;
05092 *wavestart = firstLambda;
05093 *waveend = lastLambda;
05094 }
05095 else {
05096 firstLambda = *wavestart;
05097 lastLambda = *waveend;
05098 }
05099
05100 nl = (lastLambda - firstLambda) / dispersion;
05101 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
05102 rdata = cpl_image_get_data_float(resampled);
05103
05104 if (calibration)
05105 idata = cpl_image_get_data_float(calibration);
05106
05107 if (residuals)
05108 ddata = cpl_image_get_data_float(residuals);
05109
05110 if (idscoeff)
05111 for (j = 0; j <= order; j++)
05112 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
05113
05114 if (restable) {
05115 cpl_table_set_size(restable, nref);
05116 cpl_table_new_column(restable, "wavelength", CPL_TYPE_DOUBLE);
05117 cpl_table_copy_data_double(restable, "wavelength", line);
05118 for (i = 0; i < ny; i += step) {
05119 snprintf(name, MAX_COLNAME, "r%d", i);
05120 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05121 snprintf(name, MAX_COLNAME, "d%d", i);
05122 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05123 snprintf(name, MAX_COLNAME, "p%d", i);
05124 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05125 }
05126 }
05127
05128
05129
05130
05131
05132
05133
05134 for (i = 0; i < ny; i++) {
05135 width = mos_lines_width(sdata + i*nx, nx);
05136 if (sradius > 0) {
05137 if (width > sradius) {
05138 uradius = width;
05139 }
05140 else {
05141 uradius = sradius;
05142 }
05143 }
05144 if (width < 5)
05145 width = 5;
05146 peaks = mos_peak_candidates(sdata + i*nx, nx, level, width);
05147 if (peaks) {
05148 peaks = mos_refine_peaks(sdata + i*nx, nx, peaks, width);
05149 }
05150
05151 if (peaks) {
05152 output = mos_identify_peaks(peaks, lines, min_disp,
05153 max_disp, 0.05, 2);
05154 if (output) {
05155 countLines = cpl_bivector_get_size(output);
05156 if (countLines < 4) {
05157 cpl_bivector_delete(output);
05158 cpl_vector_delete(peaks);
05159 if (nlines)
05160 nlines[i] = 0;
05161 if (error)
05162 error[i] = 0.0;
05163 continue;
05164 }
05165
05166
05167
05168
05169
05170 wavel = cpl_bivector_get_y(output);
05171 cpl_vector_subtract_scalar(wavel, refwave);
05172
05173 uorder = countLines / 2 - 1;
05174 if (uorder > order)
05175 uorder = order;
05176
05177
05178
05179
05180
05181
05182
05183
05184
05185
05186 ids = mos_poly_wav2pix(output, uorder, reject,
05187 2 * (uorder + 1), &usedLines,
05188 &ids_err);
05189
05190 if (ids == NULL) {
05191 cpl_bivector_delete(output);
05192 cpl_vector_delete(peaks);
05193 if (nlines)
05194 nlines[i] = 0;
05195 if (error)
05196 error[i] = 0.0;
05197 cpl_error_reset();
05198 continue;
05199 }
05200
05201 if (idscoeff) {
05202
05203
05204
05205
05206
05207
05208
05209 for (k = 0; k <= order; k++) {
05210 if (k > uorder) {
05211 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
05212 }
05213 else {
05214 cpl_table_set_double(idscoeff, clab[k], i,
05215 cpl_polynomial_get_coeff(ids, &k));
05216 }
05217 }
05218 }
05219
05220 if (sradius > 0) {
05221
05222
05223
05224
05225
05226 new_output = mos_find_peaks(sdata + i*nx, nx, lines,
05227 ids, refwave, uradius);
05228
05229 if (new_output) {
05230 cpl_bivector_delete(output);
05231 output = new_output;
05232 }
05233 else
05234 cpl_error_reset();
05235
05236
05237 cpl_polynomial_delete(ids);
05238
05239 countLines = cpl_bivector_get_size(output);
05240
05241 if (countLines < 4) {
05242 cpl_bivector_delete(output);
05243 cpl_vector_delete(peaks);
05244
05245
05246
05247
05248
05249
05250
05251 if (nlines)
05252 nlines[i] = 0;
05253 if (error)
05254 error[i] = 0.0;
05255 if (idscoeff)
05256 for (k = 0; k <= order; k++)
05257 cpl_table_set_invalid(idscoeff, clab[k], i);
05258 continue;
05259 }
05260
05261 wavel = cpl_bivector_get_y(output);
05262 cpl_vector_subtract_scalar(wavel, refwave);
05263
05264 uorder = countLines / 2 - 1;
05265 if (uorder > order)
05266 uorder = order;
05267
05268 ids = mos_poly_wav2pix(output, uorder, reject,
05269 2 * (uorder + 1), &usedLines,
05270 &ids_err);
05271
05272 if (ids == NULL) {
05273 cpl_bivector_delete(output);
05274 cpl_vector_delete(peaks);
05275
05276
05277
05278
05279
05280
05281
05282 if (nlines)
05283 nlines[i] = 0;
05284 if (error)
05285 error[i] = 0.0;
05286 if (idscoeff)
05287 for (k = 0; k <= order; k++)
05288 cpl_table_set_invalid(idscoeff, clab[k], i);
05289 cpl_error_reset();
05290 continue;
05291 }
05292
05293 if (idscoeff) {
05294 for (k = 0; k <= order; k++) {
05295 if (k > uorder) {
05296 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
05297 }
05298 else {
05299 cpl_table_set_double(idscoeff, clab[k], i,
05300 cpl_polynomial_get_coeff(ids, &k));
05301 }
05302 }
05303 }
05304
05305 }
05306
05307 if (nlines)
05308 nlines[i] = usedLines;
05309 if (error)
05310 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
05311
05312 pixstart = cpl_polynomial_eval_1d(ids,
05313 cpl_bivector_get_y_data(output)[0], NULL);
05314 pixend = cpl_polynomial_eval_1d(ids,
05315 cpl_bivector_get_y_data(output)[countLines-1], NULL);
05316 extrapolation = (pixend - pixstart) / 5;
05317 pixstart -= extrapolation;
05318 pixend += extrapolation;
05319 if (pixstart < 0)
05320 pixstart = 0;
05321 if (pixend > nx)
05322 pixend = nx;
05323
05324
05325
05326
05327
05328 if (calibration) {
05329 for (j = pixstart; j < pixend; j++) {
05330 (idata + i*nx)[j] = mos_eval_dds(ids, firstLambda,
05331 lastLambda, refwave,
05332 j);
05333 }
05334 }
05335
05336
05337
05338
05339
05340 for (j = 0; j < nl; j++) {
05341 lambda = firstLambda + j * dispersion;
05342 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
05343 NULL);
05344 pixel = fpixel;
05345 if (pixel >= 0 && pixel < nx-1) {
05346 v1 = (sdata + i*nx)[pixel];
05347 v2 = (sdata + i*nx)[pixel+1];
05348 vi = v1 + (v2-v1)*(fpixel-pixel);
05349 (rdata + i*nl)[j] = vi;
05350 }
05351 }
05352
05353
05354
05355
05356
05357 if (residuals || (restable && !(i%step))) {
05358 if (restable && !(i%step)) {
05359 lin = cpl_polynomial_new(1);
05360 for (k = 0; k < 2; k++)
05361 cpl_polynomial_set_coeff(lin, &k,
05362 cpl_polynomial_get_coeff(ids, &k));
05363 }
05364 for (j = 0; j < countLines; j++) {
05365 pixe = cpl_bivector_get_x_data(output)[j];
05366 wave = cpl_bivector_get_y_data(output)[j];
05367 value = pixe - cpl_polynomial_eval_1d(ids, wave, NULL);
05368 if (residuals) {
05369 pixel = pixe + 0.5;
05370 (ddata + i*nx)[pixel] = value;
05371 }
05372 if (restable && !(i%step)) {
05373 for (k = 0; k < nref; k++) {
05374 if (fabs(line[k] - refwave - wave) < 0.1) {
05375 snprintf(name, MAX_COLNAME, "r%d", i);
05376 cpl_table_set_double(restable, name,
05377 k, value);
05378 value = pixe
05379 - cpl_polynomial_eval_1d(lin, wave,
05380 NULL);
05381 snprintf(name, MAX_COLNAME, "d%d", i);
05382 cpl_table_set_double(restable, name,
05383 k, value);
05384 snprintf(name, MAX_COLNAME, "p%d", i);
05385 cpl_table_set_double(restable, name,
05386 k, pixe);
05387 break;
05388 }
05389 }
05390 }
05391 }
05392 if (restable && !(i%step)) {
05393 cpl_polynomial_delete(lin);
05394 }
05395 }
05396
05397
05398
05399
05400
05401 if (refmask) {
05402 mdata = cpl_mask_get_data(refmask);
05403 pixel = cpl_polynomial_eval_1d(ids, 0.0, NULL) + 0.5;
05404 if (pixel - 1 >= 0 && pixel + 1 < nx) {
05405 mdata[pixel-1 + i*nx] = CPL_BINARY_1;
05406 mdata[pixel + i*nx] = CPL_BINARY_1;
05407 mdata[pixel+1 + i*nx] = CPL_BINARY_1;
05408 }
05409 }
05410
05411 cpl_polynomial_delete(ids);
05412 cpl_bivector_delete(output);
05413 }
05414 cpl_vector_delete(peaks);
05415 }
05416 }
05417
05418 if (refmask) {
05419 kernel = cpl_matrix_new(3, 3);
05420 cpl_matrix_set(kernel, 0, 1, 1.0);
05421 cpl_matrix_set(kernel, 1, 1, 1.0);
05422 cpl_matrix_set(kernel, 2, 1, 1.0);
05423
05424 cpl_mask_dilation(refmask, kernel);
05425 cpl_mask_erosion(refmask, kernel);
05426 cpl_mask_erosion(refmask, kernel);
05427 cpl_mask_dilation(refmask, kernel);
05428
05429 cpl_matrix_delete(kernel);
05430
05431
05432
05433
05434
05435 mdata = cpl_mask_get_data(refmask);
05436 have_it = cpl_calloc(ny, sizeof(int));
05437
05438 for (i = 0; i < ny; i++, mdata += nx) {
05439 for (j = 0; j < nx; j++) {
05440 if (mdata[j] == CPL_BINARY_1) {
05441 have_it[i] = j;
05442 break;
05443 }
05444 }
05445 }
05446
05447 mdata = cpl_mask_get_data(refmask);
05448 in = 0;
05449 first = last = 0;
05450
05451 for (i = 0; i < ny; i++) {
05452 if (have_it[i]) {
05453 if (!in) {
05454 in = 1;
05455 if (first) {
05456 last = i;
05457 if (abs(have_it[first] - have_it[last]) < 3) {
05458 for (j = first; j < last; j++) {
05459 mdata[have_it[first] + nx*j + 0] = CPL_BINARY_1;
05460 mdata[have_it[first] + nx*j + 1] = CPL_BINARY_1;
05461 mdata[have_it[first] + nx*j + 2] = CPL_BINARY_1;
05462 }
05463 }
05464 }
05465 }
05466 }
05467 else {
05468 if (in) {
05469 in = 0;
05470 first = i - 1;
05471 }
05472 }
05473 }
05474
05475 cpl_free(have_it);
05476
05477 }
05478
05479
05480
05481
05482
05483
05484
05485
05486
05487
05488
05489 return resampled;
05490 }
05491
05492
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
05556
05557
05558
05559
05560
05561
05562
05563
05564
05565
05566
05567
05568
05569
05570
05571
05572
05573
05574
05575
05576
05577
05578
05579
05601 cpl_table *mos_locate_spectra(cpl_mask *mask)
05602 {
05603 const char *func = "mos_locate_spectra";
05604
05605 cpl_apertures *slits;
05606 cpl_image *labimage;
05607 cpl_image *refimage;
05608 cpl_table *slitpos;
05609 cpl_propertylist *sort_col;
05610 int nslits;
05611 int i;
05612
05613
05614 if (mask == NULL) {
05615 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05616 return NULL;
05617 }
05618
05619 labimage = cpl_image_labelise_mask_create(mask, &nslits);
05620
05621 if (nslits < 1) {
05622 cpl_image_delete(labimage);
05623 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05624 return NULL;
05625 }
05626
05627 refimage = cpl_image_new_from_mask(mask);
05628
05629 slits = cpl_apertures_new_from_image(refimage, labimage);
05630
05631 cpl_image_delete(labimage);
05632 cpl_image_delete(refimage);
05633
05634 nslits = cpl_apertures_get_size(slits);
05635 if (nslits < 1) {
05636 cpl_apertures_delete(slits);
05637 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05638 return NULL;
05639 }
05640
05641 slitpos = cpl_table_new(nslits);
05642 cpl_table_new_column(slitpos, "xtop", CPL_TYPE_DOUBLE);
05643 cpl_table_new_column(slitpos, "ytop", CPL_TYPE_DOUBLE);
05644 cpl_table_new_column(slitpos, "xbottom", CPL_TYPE_DOUBLE);
05645 cpl_table_new_column(slitpos, "ybottom", CPL_TYPE_DOUBLE);
05646 cpl_table_set_column_unit(slitpos, "xtop", "pixel");
05647 cpl_table_set_column_unit(slitpos, "ytop", "pixel");
05648 cpl_table_set_column_unit(slitpos, "xbottom", "pixel");
05649 cpl_table_set_column_unit(slitpos, "ybottom", "pixel");
05650
05651 for (i = 0; i < nslits; i++) {
05652 cpl_table_set_double(slitpos, "xtop", i,
05653 cpl_apertures_get_top_x(slits, i+1) - 1);
05654 cpl_table_set_double(slitpos, "ytop", i,
05655 cpl_apertures_get_top(slits, i+1));
05656 cpl_table_set_double(slitpos, "xbottom", i,
05657 cpl_apertures_get_bottom_x(slits, i+1) - 1);
05658 cpl_table_set_double(slitpos, "ybottom", i,
05659 cpl_apertures_get_bottom(slits, i+1));
05660 }
05661
05662 cpl_apertures_delete(slits);
05663
05664 sort_col = cpl_propertylist_new();
05665 cpl_propertylist_append_bool(sort_col, "ytop", 1);
05666 cpl_table_sort(slitpos, sort_col);
05667 cpl_propertylist_delete(sort_col);
05668
05669 return slitpos;
05670
05671 }
05672
05673
05689 cpl_error_code mos_validate_slits(cpl_table *slits)
05690 {
05691 const char *func = "mos_validate_slits";
05692
05693
05694 if (slits == NULL)
05695 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05696
05697 if (1 != cpl_table_has_column(slits, "xtop"))
05698 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05699
05700 if (1 != cpl_table_has_column(slits, "ytop"))
05701 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05702
05703 if (1 != cpl_table_has_column(slits, "xbottom"))
05704 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05705
05706 if (1 != cpl_table_has_column(slits, "ybottom"))
05707 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05708
05709 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "xtop"))
05710 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05711
05712 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "ytop"))
05713 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05714
05715 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "xbottom"))
05716 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05717
05718 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "ybottom"))
05719 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05720
05721 return CPL_ERROR_NONE;
05722 }
05723
05724
05753 cpl_error_code mos_rotate_slits(cpl_table *slits, int rotation, int nx, int ny)
05754 {
05755 const char *func = "mos_rotate_slits";
05756
05757 cpl_error_code error;
05758 char aux_name[] = "_0";
05759 int i;
05760
05761
05762 rotation %= 4;
05763 if (rotation < 0)
05764 rotation += 4;
05765
05766 if (rotation == 0)
05767 return CPL_ERROR_NONE;
05768
05769 error = mos_validate_slits(slits);
05770 if (error)
05771 return cpl_error_set(func, error);
05772
05773 if (rotation == 1 || rotation == 3) {
05774
05775
05776
05777
05778
05779 for (i = 0; i < 77; i++)
05780 if (1 == cpl_table_has_column(slits, aux_name))
05781 aux_name[1]++;
05782 if (1 == cpl_table_has_column(slits, aux_name))
05783 return cpl_error_set(func, CPL_ERROR_CONTINUE);
05784 cpl_table_name_column(slits, "xtop", aux_name);
05785 cpl_table_name_column(slits, "ytop", "xtop");
05786 cpl_table_name_column(slits, aux_name, "ytop");
05787 cpl_table_name_column(slits, "xbottom", aux_name);
05788 cpl_table_name_column(slits, "ybottom", "xbottom");
05789 cpl_table_name_column(slits, aux_name, "ybottom");
05790 }
05791
05792 if (rotation == 1 || rotation == 2) {
05793 cpl_table_multiply_scalar(slits, "xtop", -1.0);
05794 cpl_table_multiply_scalar(slits, "xbottom", -1.0);
05795 cpl_table_add_scalar(slits, "xtop", nx);
05796 cpl_table_add_scalar(slits, "xbottom", nx);
05797 }
05798
05799 if (rotation == 3 || rotation == 2) {
05800 cpl_table_multiply_scalar(slits, "ytop", -1.0);
05801 cpl_table_multiply_scalar(slits, "ybottom", -1.0);
05802 cpl_table_add_scalar(slits, "ytop", ny);
05803 cpl_table_add_scalar(slits, "ybottom", ny);
05804 }
05805
05806 return CPL_ERROR_NONE;
05807 }
05808
05809
05867 cpl_table *mos_identify_slits(cpl_table *slits, cpl_table *maskslits,
05868 cpl_table *global)
05869 {
05870 cpl_array *top_ident;
05871 cpl_array *bot_ident;
05872 cpl_matrix *mdata;
05873 cpl_matrix *mpattern;
05874 cpl_matrix *top_data;
05875 cpl_matrix *top_pattern;
05876 cpl_matrix *top_mdata;
05877 cpl_matrix *top_mpattern;
05878 cpl_matrix *bot_data;
05879 cpl_matrix *bot_pattern;
05880 cpl_matrix *bot_mdata;
05881 cpl_matrix *bot_mpattern;
05882 cpl_propertylist *sort_col;
05883 double *xtop;
05884 double *ytop;
05885 double *xmtop;
05886 double *ymtop;
05887 double *xbot;
05888 double *ybot;
05889 double *xmbot;
05890 double *ymbot;
05891 double top_scale, bot_scale;
05892 double angle, top_angle, bot_angle;
05893 double xmse, ymse;
05894 double xrms, top_xrms, bot_xrms;
05895 double yrms, top_yrms, bot_yrms;
05896 int nslits;
05897 int nmaskslits, use_pattern;
05898 int found_slits, found_slits_top, found_slits_bot;
05899 int degree;
05900 int i;
05901 cpl_table *positions;
05902 cpl_error_code error;
05903
05904 cpl_vector *point;
05905 double *dpoint;
05906 cpl_vector *xpos;
05907 cpl_vector *ypos;
05908 cpl_vector *xmpos;
05909 cpl_vector *ympos;
05910 cpl_bivector *mpos;
05911 cpl_polynomial *xpoly = NULL;
05912 cpl_polynomial *ypoly = NULL;
05913 cpl_polynomial *top_xpoly = NULL;
05914 cpl_polynomial *top_ypoly = NULL;
05915 cpl_polynomial *bot_xpoly = NULL;
05916 cpl_polynomial *bot_ypoly = NULL;
05917
05918
05919 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 3, 0)
05920 positions = mos_identify_slits_fast(slits, maskslits, global);
05921 if (positions == NULL)
05922 cpl_error_set_where(cpl_func);
05923 return positions;
05924 #endif
05925
05926 error = mos_validate_slits(slits);
05927 if (error) {
05928 cpl_msg_error(cpl_func, "CCD slits table validation: %s",
05929 cpl_error_get_message());
05930 cpl_error_set(cpl_func, error);
05931 return NULL;
05932 }
05933
05934 error = mos_validate_slits(maskslits);
05935 if (error) {
05936 cpl_msg_error(cpl_func, "Mask slits table validation: %s",
05937 cpl_error_get_message());
05938 cpl_error_set(cpl_func, error);
05939 return NULL;
05940 }
05941
05942 if (1 != cpl_table_has_column(maskslits, "slit_id")) {
05943 cpl_msg_error(cpl_func, "Missing slits identifiers");
05944 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
05945 return NULL;
05946 }
05947
05948 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits, "slit_id")) {
05949 cpl_msg_error(cpl_func, "Wrong type used for slits identifiers");
05950 cpl_error_set(cpl_func, CPL_ERROR_INVALID_TYPE);
05951 return NULL;
05952 }
05953
05954 nslits = cpl_table_get_nrow(slits);
05955 nmaskslits = cpl_table_get_nrow(maskslits);
05956
05957 if (nslits == 0 || nmaskslits == 0) {
05958 cpl_msg_error(cpl_func, "Empty slits table");
05959 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
05960 return NULL;
05961 }
05962
05963 if (nslits > 25) {
05964 cpl_msg_info(cpl_func, "Many slits: using 'fast' pattern matching...");
05965 positions = mos_identify_slits_fast(slits, maskslits, global);
05966 if (positions == NULL)
05967 cpl_error_set_where(cpl_func);
05968 return positions;
05969 }
05970
05971
05972
05973
05974
05975 sort_col = cpl_propertylist_new();
05976 cpl_propertylist_append_bool(sort_col, "ytop", 1);
05977 cpl_table_sort(slits, sort_col);
05978 cpl_table_sort(maskslits, sort_col);
05979 cpl_propertylist_delete(sort_col);
05980
05981
05982
05983
05984
05985 if (nslits < 3 && nmaskslits > nslits) {
05986
05987
05988
05989
05990
05991
05992
05993
05994 if (nslits > 1)
05995 cpl_msg_warning(cpl_func, "Cannot match the %d found CCD slits "
05996 "with the %d mask slits: process will continue "
05997 "using the detected CCD slits positions", nslits,
05998 nmaskslits);
05999 else
06000 cpl_msg_warning(cpl_func, "Cannot match the found CCD slit with "
06001 "the %d mask slits: process will continue using "
06002 "the detected CCD slit position", nmaskslits);
06003 return NULL;
06004 }
06005
06006 if (nmaskslits < 3 && nslits > nmaskslits) {
06007
06008
06009
06010
06011
06012
06013
06014 cpl_msg_warning(cpl_func, "Cannot match the %d found CCD slits with "
06015 "the %d mask slits: process will continue using "
06016 "the detected CCD slits positions", nslits,
06017 nmaskslits);
06018 return NULL;
06019 }
06020
06021
06022
06023
06024
06025
06026
06027
06028 xtop = cpl_table_get_data_double(slits, "xtop");
06029 ytop = cpl_table_get_data_double(slits, "ytop");
06030 xmtop = cpl_table_get_data_double(maskslits, "xtop");
06031 ymtop = cpl_table_get_data_double(maskslits, "ytop");
06032
06033 xbot = cpl_table_get_data_double(slits, "xbottom");
06034 ybot = cpl_table_get_data_double(slits, "ybottom");
06035 xmbot = cpl_table_get_data_double(maskslits, "xbottom");
06036 ymbot = cpl_table_get_data_double(maskslits, "ybottom");
06037
06038 top_data = cpl_matrix_new(2, nslits);
06039 top_pattern = cpl_matrix_new(2, nmaskslits);
06040 bot_data = cpl_matrix_new(2, nslits);
06041 bot_pattern = cpl_matrix_new(2, nmaskslits);
06042
06043 for (i = 0; i < nslits; i++)
06044 cpl_matrix_set(top_data, 0, i, xtop[i]);
06045
06046 for (i = 0; i < nslits; i++)
06047 cpl_matrix_set(top_data, 1, i, ytop[i]);
06048
06049 for (i = 0; i < nmaskslits; i++)
06050 cpl_matrix_set(top_pattern, 0, i, xmtop[i]);
06051
06052 for (i = 0; i < nmaskslits; i++)
06053 cpl_matrix_set(top_pattern, 1, i, ymtop[i]);
06054
06055 for (i = 0; i < nslits; i++)
06056 cpl_matrix_set(bot_data, 0, i, xbot[i]);
06057
06058 for (i = 0; i < nslits; i++)
06059 cpl_matrix_set(bot_data, 1, i, ybot[i]);
06060
06061 for (i = 0; i < nmaskslits; i++)
06062 cpl_matrix_set(bot_pattern, 0, i, xmbot[i]);
06063
06064 for (i = 0; i < nmaskslits; i++)
06065 cpl_matrix_set(bot_pattern, 1, i, ymbot[i]);
06066
06067 if (nmaskslits > nslits)
06068 use_pattern = nslits;
06069 else
06070 use_pattern = nmaskslits;
06071
06072 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 3, 0)
06073 top_ident = cpl_ppm_match_points(top_data, nslits, 1.0, top_pattern,
06074 use_pattern, 0.0, 0.1, 5, &top_mdata,
06075 &top_mpattern, &top_scale, &top_angle);
06076
06077 bot_ident = cpl_ppm_match_points(bot_data, nslits, 1.0, bot_pattern,
06078 use_pattern, 0.0, 0.1, 5, &bot_mdata,
06079 &bot_mpattern, &bot_scale, &bot_angle);
06080 #else
06081 top_ident = NULL;
06082 bot_ident = NULL;
06083 #endif
06084
06085 if (top_ident == NULL && bot_ident == NULL) {
06086 cpl_msg_warning(cpl_func, "Pattern matching failure: cannot match "
06087 "the %d found CCD slits with the %d mask slits: "
06088 "process will continue using the detected CCD "
06089 "slits positions", nslits, nmaskslits);
06090 return NULL;
06091 }
06092
06093 found_slits_top = 0;
06094 found_slits_bot = 0;
06095 if (top_ident && bot_ident) {
06096 cpl_msg_info(cpl_func, "Median platescale: %f +/- %f pixel/mm",
06097 (top_scale + bot_scale) / 2, fabs(top_scale - bot_scale));
06098 cpl_msg_info(cpl_func, "Median rotation: %f +/- %f degrees",
06099 (top_angle + bot_angle) / 2, fabs(top_angle - bot_angle));
06100 if (fabs(top_angle) < fabs(bot_angle))
06101 angle = fabs(top_angle);
06102 else
06103 angle = fabs(bot_angle);
06104 found_slits_top = cpl_matrix_get_ncol(top_mdata);
06105 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
06106 }
06107 else if (top_ident) {
06108 cpl_msg_info(cpl_func, "Median platescale: %f pixel/mm", top_scale);
06109 cpl_msg_info(cpl_func, "Median rotation: %f degrees", top_angle);
06110 angle = fabs(top_angle);
06111 found_slits_top = cpl_matrix_get_ncol(top_mdata);
06112 }
06113 else {
06114 cpl_msg_info(cpl_func, "Median platescale: %f pixel/mm", bot_scale);
06115 cpl_msg_info(cpl_func, "Median rotation: %f degrees", bot_angle);
06116 angle = fabs(bot_angle);
06117 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
06118 }
06119
06120 cpl_array_delete(top_ident);
06121 cpl_array_delete(bot_ident);
06122
06123 if (angle > 4.0) {
06124 cpl_msg_warning(cpl_func, "Uncertain pattern matching: the rotation "
06125 "angle is expected to be around zero. This match is "
06126 "rejected: the process will continue using the %d "
06127 "detected CCD slits positions", nslits);
06128 return NULL;
06129 }
06130
06131 found_slits = found_slits_top;
06132 if (found_slits < found_slits_bot)
06133 found_slits = found_slits_bot;
06134
06135 if (found_slits < 4) {
06136 cpl_msg_warning(cpl_func,
06137 "Too few safely identified slits: %d out of %d "
06138 "candidates (%d expected). Process will continue "
06139 "using the detected CCD slits positions", found_slits,
06140 nslits, nmaskslits);
06141 return NULL;
06142 }
06143
06144 cpl_msg_info(cpl_func, "Preliminary identified slits: %d out of %d "
06145 "candidates\n(%d expected)", found_slits, nslits,
06146 nmaskslits);
06147
06148 if (found_slits_top < 4)
06149 found_slits_top = 0;
06150
06151 if (found_slits_bot < 4)
06152 found_slits_bot = 0;
06153
06154
06155
06156
06157
06158
06159
06160 for (i = 0; i < 2; i++) {
06161 if (i) {
06162 found_slits = found_slits_top;
06163 mdata = top_mdata;
06164 mpattern = top_mpattern;
06165 }
06166 else {
06167 found_slits = found_slits_bot;
06168 mdata = bot_mdata;
06169 mpattern = bot_mpattern;
06170 }
06171
06172 if (found_slits == 0)
06173 continue;
06174 else if (found_slits < 10)
06175 degree = 1;
06176 else
06177 degree = 2;
06178
06179 xpos = cpl_vector_wrap(found_slits,
06180 cpl_matrix_get_data(mdata) );
06181 ypos = cpl_vector_wrap(found_slits,
06182 cpl_matrix_get_data(mdata) + found_slits);
06183 xmpos = cpl_vector_wrap(found_slits,
06184 cpl_matrix_get_data(mpattern) );
06185 ympos = cpl_vector_wrap(found_slits,
06186 cpl_matrix_get_data(mpattern) + found_slits);
06187 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
06188 xpoly = cpl_polynomial_fit_2d_create(mpos, xpos, degree, &xmse);
06189 ypoly = cpl_polynomial_fit_2d_create(mpos, ypos, degree, &ymse);
06190
06191 cpl_bivector_unwrap_vectors(mpos);
06192 cpl_vector_unwrap(xpos);
06193 cpl_vector_unwrap(ypos);
06194 cpl_vector_unwrap(xmpos);
06195 cpl_vector_unwrap(ympos);
06196 cpl_matrix_delete(mdata);
06197 cpl_matrix_delete(mpattern);
06198
06199 if (i) {
06200 top_xpoly = xpoly;
06201 top_ypoly = ypoly;
06202 top_xrms = sqrt(xmse*2*degree/(found_slits - 1));
06203 top_yrms = sqrt(ymse*2*degree/(found_slits - 1));
06204 }
06205 else {
06206 bot_xpoly = xpoly;
06207 bot_ypoly = ypoly;
06208 bot_xrms = sqrt(xmse*2*degree/(found_slits - 1));
06209 bot_yrms = sqrt(ymse*2*degree/(found_slits - 1));
06210 }
06211 }
06212
06213 if (top_xpoly && bot_xpoly) {
06214 if (top_xrms < bot_xrms) {
06215 xrms = top_xrms;
06216 xpoly = top_xpoly;
06217 cpl_polynomial_delete(bot_xpoly);
06218 }
06219 else {
06220 xrms = bot_xrms;
06221 xpoly = bot_xpoly;
06222 cpl_polynomial_delete(top_xpoly);
06223 }
06224 }
06225 else if (top_xpoly) {
06226 xrms = top_xrms;
06227 xpoly = top_xpoly;
06228 }
06229 else {
06230 xrms = bot_xrms;
06231 xpoly = bot_xpoly;
06232 }
06233
06234 if (top_ypoly && bot_ypoly) {
06235 if (top_yrms < bot_yrms) {
06236 yrms = top_yrms;
06237 ypoly = top_ypoly;
06238 cpl_polynomial_delete(bot_ypoly);
06239 }
06240 else {
06241 yrms = bot_yrms;
06242 ypoly = bot_ypoly;
06243 cpl_polynomial_delete(top_ypoly);
06244 }
06245 }
06246 else if (top_ypoly) {
06247 yrms = top_yrms;
06248 ypoly = top_ypoly;
06249 }
06250 else {
06251 yrms = bot_yrms;
06252 ypoly = bot_ypoly;
06253 }
06254
06255 if (xpoly == NULL || ypoly == NULL) {
06256 cpl_msg_warning(cpl_func, "Fit failure: the accuracy of the "
06257 "identified slits positions cannot be improved.");
06258 cpl_polynomial_delete(xpoly);
06259 cpl_polynomial_delete(ypoly);
06260 cpl_error_reset();
06261 return NULL;
06262 }
06263
06264 cpl_msg_info(cpl_func,
06265 "Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
06266 xrms, yrms);
06267
06268 if (global) {
06269 write_global_distortion(global, 0, xpoly);
06270 write_global_distortion(global, 7, ypoly);
06271 }
06272
06273
06274
06275
06276
06277
06278 positions = cpl_table_duplicate(maskslits);
06279 cpl_table_duplicate_column(positions, "xmtop", positions, "xtop");
06280 cpl_table_duplicate_column(positions, "ymtop", positions, "ytop");
06281 cpl_table_duplicate_column(positions, "xmbottom", positions, "xbottom");
06282 cpl_table_duplicate_column(positions, "ymbottom", positions, "ybottom");
06283
06284 point = cpl_vector_new(2);
06285 dpoint = cpl_vector_get_data(point);
06286
06287 for (i = 0; i < nmaskslits; i++) {
06288 dpoint[0] = cpl_table_get_double(positions, "xmtop", i, NULL);
06289 dpoint[1] = cpl_table_get_double(positions, "ymtop", i, NULL);
06290 cpl_table_set_double(positions, "xtop", i,
06291 cpl_polynomial_eval(xpoly, point));
06292 cpl_table_set_double(positions, "ytop", i,
06293 cpl_polynomial_eval(ypoly, point));
06294 dpoint[0] = cpl_table_get_double(positions, "xmbottom", i, NULL);
06295 dpoint[1] = cpl_table_get_double(positions, "ymbottom", i, NULL);
06296 cpl_table_set_double(positions, "xbottom", i,
06297 cpl_polynomial_eval(xpoly, point));
06298 cpl_table_set_double(positions, "ybottom", i,
06299 cpl_polynomial_eval(ypoly, point));
06300 }
06301
06302 cpl_vector_delete(point);
06303 cpl_polynomial_delete(xpoly);
06304 cpl_polynomial_delete(ypoly);
06305
06306 cpl_table_erase_column(positions, "xmtop");
06307 cpl_table_erase_column(positions, "ymtop");
06308 cpl_table_erase_column(positions, "xmbottom");
06309 cpl_table_erase_column(positions, "ymbottom");
06310
06311 if (nmaskslits > nslits)
06312 cpl_msg_info(cpl_func,
06313 "Finally identified slits: %d out of %d expected\n"
06314 "(%d recovered)", nmaskslits, nmaskslits,
06315 nmaskslits - nslits);
06316 else if (nmaskslits < nslits)
06317 cpl_msg_info(cpl_func,
06318 "Finally identified slits: %d out of %d expected\n"
06319 "(%d rejected)", nmaskslits, nmaskslits,
06320 nslits - nmaskslits);
06321 else
06322 cpl_msg_info(cpl_func,
06323 "Finally identified slits: %d out of %d expected",
06324 nmaskslits, nmaskslits);
06325
06326 return positions;
06327
06328 }
06329
06330
06331 cpl_table *mos_identify_slits_fast(cpl_table *slits, cpl_table *maskslits,
06332 cpl_table *global)
06333 {
06334 const char *func = "mos_identify_slits_fast";
06335
06336 cpl_propertylist *sort_col;
06337 cpl_table *positions;
06338 cpl_vector *scales;
06339 cpl_vector *angles;
06340 cpl_vector *point;
06341 cpl_vector *xpos;
06342 cpl_vector *ypos;
06343 cpl_vector *xmpos;
06344 cpl_vector *ympos;
06345 cpl_bivector *mpos;
06346 cpl_polynomial *xpoly = NULL;
06347 cpl_polynomial *ypoly = NULL;
06348 cpl_error_code error;
06349 int nslits;
06350 int nmaskslits;
06351 int found_slits;
06352 int i, j, k;
06353
06354 double dist1, dist2, dist3, dist, mindist;
06355 double scale, minscale, maxscale;
06356 double angle, minangle, maxangle;
06357 double *dscale;
06358 double *dangle;
06359 double *dpoint;
06360 double *xtop;
06361 double *ytop;
06362 double *xbottom;
06363 double *ybottom;
06364 double *xcenter;
06365 double *ycenter;
06366 double *xpseudo;
06367 double *ypseudo;
06368 int *slit_id;
06369 double *xmtop;
06370 double *ymtop;
06371 double *xmbottom;
06372 double *ymbottom;
06373 double *xmcenter;
06374 double *ymcenter;
06375 double *xmpseudo;
06376 double *ympseudo;
06377 double xmse, ymse;
06378 int *mslit_id;
06379 int *good;
06380 int minpos;
06381 int degree;
06382
06383 double sradius = 0.01;
06384 int in_sradius;
06385
06386 double pi = 3.14159265358979323846;
06387
06388
06389 error = mos_validate_slits(slits);
06390 if (error) {
06391 cpl_msg_error(func, "CCD slits table validation: %s",
06392 cpl_error_get_message());
06393 cpl_error_set(func, error);
06394 return NULL;
06395 }
06396
06397 error = mos_validate_slits(maskslits);
06398 if (error) {
06399 cpl_msg_error(func, "Mask slits table validation: %s",
06400 cpl_error_get_message());
06401 cpl_error_set(func, error);
06402 return NULL;
06403 }
06404
06405 if (1 != cpl_table_has_column(maskslits, "slit_id")) {
06406 cpl_msg_error(func, "Missing slits identifiers");
06407 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
06408 return NULL;
06409 }
06410
06411 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits, "slit_id")) {
06412 cpl_msg_error(func, "Wrong type used for slits identifiers");
06413 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
06414 return NULL;
06415 }
06416
06417 nslits = cpl_table_get_nrow(slits);
06418 nmaskslits = cpl_table_get_nrow(maskslits);
06419
06420 if (nslits == 0 || nmaskslits == 0) {
06421 cpl_msg_error(func, "Empty slits table");
06422 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
06423 return NULL;
06424 }
06425
06426
06427
06428
06429
06430
06431
06432 if (cpl_table_has_column(slits, "xcenter"))
06433 cpl_table_erase_column(slits, "xcenter");
06434
06435 if (cpl_table_has_column(slits, "ycenter"))
06436 cpl_table_erase_column(slits, "ycenter");
06437
06438 if (cpl_table_has_column(maskslits, "xcenter"))
06439 cpl_table_erase_column(maskslits, "xcenter");
06440
06441 if (cpl_table_has_column(maskslits, "ycenter"))
06442 cpl_table_erase_column(maskslits, "ycenter");
06443
06444 cpl_table_duplicate_column(slits, "xcenter", slits, "xtop");
06445 cpl_table_add_columns(slits, "xcenter", "xbottom");
06446 cpl_table_divide_scalar(slits, "xcenter", 2.0);
06447 cpl_table_duplicate_column(slits, "ycenter", slits, "ytop");
06448 cpl_table_add_columns(slits, "ycenter", "ybottom");
06449 cpl_table_divide_scalar(slits, "ycenter", 2.0);
06450
06451 cpl_table_duplicate_column(maskslits, "xcenter", maskslits, "xtop");
06452 cpl_table_add_columns(maskslits, "xcenter", "xbottom");
06453 cpl_table_divide_scalar(maskslits, "xcenter", 2.0);
06454 cpl_table_duplicate_column(maskslits, "ycenter", maskslits, "ytop");
06455 cpl_table_add_columns(maskslits, "ycenter", "ybottom");
06456 cpl_table_divide_scalar(maskslits, "ycenter", 2.0);
06457
06458
06459
06460
06461
06462
06463 sort_col = cpl_propertylist_new();
06464 cpl_propertylist_append_bool(sort_col, "ycenter", 1);
06465 cpl_table_sort(slits, sort_col);
06466 cpl_table_sort(maskslits, sort_col);
06467 cpl_propertylist_delete(sort_col);
06468
06469
06470
06471
06472
06473
06474 if (nslits < 3 && nmaskslits > nslits) {
06475
06476
06477
06478
06479
06480
06481
06482
06483 if (nslits > 1)
06484 cpl_msg_warning(func, "Cannot match the found CCD slit with the "
06485 "%d mask slits: process will continue using the "
06486 "detected CCD slit position", nmaskslits);
06487 else
06488 cpl_msg_warning(func, "Cannot match the %d found CCD slits with "
06489 "the %d mask slits: process will continue using "
06490 "the detected CCD slits positions", nslits,
06491 nmaskslits);
06492 return NULL;
06493 }
06494
06495 if (nslits <= 3 && nslits == nmaskslits) {
06496
06497 cpl_msg_warning(func, "Too few slits (%d) on mask and CCD", nslits);
06498 cpl_msg_warning(func, "Their detected positions are left unchanged");
06499
06500
06501
06502
06503
06504
06505
06506
06507
06508
06509 positions = cpl_table_duplicate(slits);
06510 cpl_table_erase_column(slits, "xcenter");
06511 cpl_table_erase_column(slits, "ycenter");
06512 cpl_table_duplicate_column(positions, "xmtop", maskslits, "xtop");
06513 cpl_table_duplicate_column(positions, "ymtop", maskslits, "ytop");
06514 cpl_table_duplicate_column(positions, "xmbottom", maskslits, "xbottom");
06515 cpl_table_duplicate_column(positions, "ymbottom", maskslits, "ybottom");
06516 cpl_table_duplicate_column(positions, "xmcenter", maskslits, "xcenter");
06517 cpl_table_duplicate_column(positions, "ymcenter", maskslits, "ycenter");
06518 cpl_table_duplicate_column(positions, "slit_id", maskslits, "slit_id");
06519 cpl_table_erase_column(maskslits, "xcenter");
06520 cpl_table_erase_column(maskslits, "ycenter");
06521
06522 if (nslits > 1) {
06523 xcenter = cpl_table_get_data_double(positions, "xcenter");
06524 ycenter = cpl_table_get_data_double(positions, "ycenter");
06525 xmcenter = cpl_table_get_data_double(positions, "xmcenter");
06526 ymcenter = cpl_table_get_data_double(positions, "ymcenter");
06527
06528 dist1 = (xcenter[0] - xcenter[1])*(xcenter[0] - xcenter[1])
06529 + (ycenter[0] - ycenter[1])*(ycenter[0] - ycenter[1]);
06530 dist2 = (xmcenter[0] - xmcenter[1])*(xmcenter[0] - xmcenter[1])
06531 + (ymcenter[0] - ymcenter[1])*(ymcenter[0] - ymcenter[1]);
06532 scale = sqrt(dist1/dist2);
06533
06534 if (nslits == 3) {
06535 dist1 = (xcenter[1] - xcenter[2])*(xcenter[1] - xcenter[2])
06536 + (ycenter[1] - ycenter[2])*(ycenter[1] - ycenter[2]);
06537 dist2 = (xmcenter[1] - xmcenter[2])*(xmcenter[1] - xmcenter[2])
06538 + (ymcenter[1] - ymcenter[2])*(ymcenter[1] - ymcenter[2]);
06539 scale += sqrt(dist1/dist2);
06540 scale /= 2;
06541 }
06542
06543 cpl_msg_info(func, "Platescale: %f pixel/mm", scale);
06544 }
06545
06546 return positions;
06547 }
06548
06549 if (nmaskslits < 3 && nslits > nmaskslits) {
06550
06551
06552
06553
06554
06555
06556
06557 cpl_msg_warning(func, "Cannot match the %d found CCD slits with "
06558 "the %d mask slits: process will continue using "
06559 "the detected CCD slits positions", nslits,
06560 nmaskslits);
06561 return NULL;
06562 }
06563
06564
06565
06566
06567
06568
06569
06570
06571
06572
06573
06574
06575
06576
06577
06578
06579
06580
06581
06582
06583
06584
06585
06586
06587
06588
06589
06590
06591 if (cpl_table_has_column(slits, "xpseudo"))
06592 cpl_table_erase_column(slits, "xpseudo");
06593
06594 if (cpl_table_has_column(slits, "ypseudo"))
06595 cpl_table_erase_column(slits, "ypseudo");
06596
06597 if (cpl_table_has_column(maskslits, "xpseudo"))
06598 cpl_table_erase_column(maskslits, "xpseudo");
06599
06600 if (cpl_table_has_column(maskslits, "ypseudo"))
06601 cpl_table_erase_column(maskslits, "ypseudo");
06602
06603 cpl_table_duplicate_column(slits, "xpseudo", slits, "xcenter");
06604 cpl_table_duplicate_column(slits, "ypseudo", slits, "ycenter");
06605
06606 xcenter = cpl_table_get_data_double(slits, "xcenter");
06607 ycenter = cpl_table_get_data_double(slits, "ycenter");
06608 xpseudo = cpl_table_get_data_double(slits, "xpseudo");
06609 ypseudo = cpl_table_get_data_double(slits, "ypseudo");
06610
06611 for (i = 1; i < nslits - 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 xpseudo[i] = sqrt(dist1/dist2);
06619 ypseudo[i] = sqrt(dist3/dist2);
06620 }
06621
06622 cpl_table_set_invalid(slits, "xpseudo", 0);
06623 cpl_table_set_invalid(slits, "xpseudo", nslits-1);
06624 cpl_table_set_invalid(slits, "ypseudo", 0);
06625 cpl_table_set_invalid(slits, "ypseudo", nslits-1);
06626
06627 cpl_table_duplicate_column(maskslits, "xpseudo", maskslits, "xcenter");
06628 cpl_table_duplicate_column(maskslits, "ypseudo", maskslits, "ycenter");
06629
06630 xcenter = cpl_table_get_data_double(maskslits, "xcenter");
06631 ycenter = cpl_table_get_data_double(maskslits, "ycenter");
06632 xmpseudo = cpl_table_get_data_double(maskslits, "xpseudo");
06633 ympseudo = cpl_table_get_data_double(maskslits, "ypseudo");
06634
06635 for (i = 1; i < nmaskslits - 1; i++) {
06636 dist1 = (xcenter[i-1] - xcenter[i])*(xcenter[i-1] - xcenter[i])
06637 + (ycenter[i-1] - ycenter[i])*(ycenter[i-1] - ycenter[i]);
06638 dist2 = (xcenter[i-1] - xcenter[i+1])*(xcenter[i-1] - xcenter[i+1])
06639 + (ycenter[i-1] - ycenter[i+1])*(ycenter[i-1] - ycenter[i+1]);
06640 dist3 = (xcenter[i] - xcenter[i+1])*(xcenter[i] - xcenter[i+1])
06641 + (ycenter[i] - ycenter[i+1])*(ycenter[i] - ycenter[i+1]);
06642 xmpseudo[i] = sqrt(dist1/dist2);
06643 ympseudo[i] = sqrt(dist3/dist2);
06644 }
06645
06646 cpl_table_set_invalid(maskslits, "xpseudo", 0);
06647 cpl_table_set_invalid(maskslits, "xpseudo", nmaskslits-1);
06648 cpl_table_set_invalid(maskslits, "ypseudo", 0);
06649 cpl_table_set_invalid(maskslits, "ypseudo", nmaskslits-1);
06650
06651
06652
06653
06654
06655
06656
06657
06658
06659
06660
06661 if (cpl_table_has_column(slits, "slit_id"))
06662 cpl_table_erase_column(slits, "slit_id");
06663 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
06664 slit_id = cpl_table_get_data_int(maskslits, "slit_id");
06665
06666 for (i = 1; i < nmaskslits - 1; i++) {
06667 in_sradius = 0;
06668 mindist = (xmpseudo[i] - xpseudo[1]) * (xmpseudo[i] - xpseudo[1])
06669 + (ympseudo[i] - ypseudo[1]) * (ympseudo[i] - ypseudo[1]);
06670 minpos = 1;
06671 if (mindist < sradius*sradius)
06672 in_sradius++;
06673 for (j = 2; j < nslits - 1; j++) {
06674 dist = (xmpseudo[i] - xpseudo[j]) * (xmpseudo[i] - xpseudo[j])
06675 + (ympseudo[i] - ypseudo[j]) * (ympseudo[i] - ypseudo[j]);
06676 if (dist < sradius*sradius)
06677 in_sradius++;
06678 if (in_sradius > 1)
06679 break;
06680 if (mindist > dist) {
06681 mindist = dist;
06682 minpos = j;
06683 }
06684 }
06685
06686 mindist = sqrt(mindist);
06687
06688 if (mindist < sradius && in_sradius == 1) {
06689 cpl_table_set_int(slits, "slit_id", minpos-1, slit_id[i-1]);
06690 cpl_table_set_int(slits, "slit_id", minpos, slit_id[i]);
06691 cpl_table_set_int(slits, "slit_id", minpos+1, slit_id[i+1]);
06692 }
06693 }
06694
06695
06696
06697
06698
06699
06700
06701 found_slits = nslits - cpl_table_count_invalid(slits, "slit_id");
06702
06703 if (found_slits < 3) {
06704 cpl_msg_warning(func, "Too few preliminarily identified slits: "
06705 "%d out of %d", found_slits, nslits);
06706 if (nslits == nmaskslits) {
06707 cpl_msg_warning(func, "(this is not an error, it could be caused "
06708 "by a mask with regularly located slits)");
06709 cpl_msg_warning(func, "The detected slits positions are left "
06710 "unchanged");
06711
06712
06713
06714
06715
06716
06717
06718
06719 cpl_table_erase_column(slits, "slit_id");
06720 cpl_table_erase_column(slits, "xpseudo");
06721 cpl_table_erase_column(slits, "ypseudo");
06722 positions = cpl_table_duplicate(slits);
06723 cpl_table_erase_column(slits, "xcenter");
06724 cpl_table_erase_column(slits, "ycenter");
06725
06726 cpl_table_erase_column(maskslits, "xpseudo");
06727 cpl_table_erase_column(maskslits, "ypseudo");
06728 cpl_table_duplicate_column(positions, "xmtop",
06729 maskslits, "xtop");
06730 cpl_table_duplicate_column(positions, "ymtop",
06731 maskslits, "ytop");
06732 cpl_table_duplicate_column(positions, "xmbottom",
06733 maskslits, "xbottom");
06734 cpl_table_duplicate_column(positions, "ymbottom",
06735 maskslits, "ybottom");
06736 cpl_table_duplicate_column(positions, "xmcenter",
06737 maskslits, "xcenter");
06738 cpl_table_duplicate_column(positions, "ymcenter",
06739 maskslits, "ycenter");
06740 cpl_table_duplicate_column(positions, "slit_id",
06741 maskslits, "slit_id");
06742 cpl_table_erase_column(maskslits, "xcenter");
06743 cpl_table_erase_column(maskslits, "ycenter");
06744 return positions;
06745 }
06746 else {
06747 cpl_table_erase_column(slits, "slit_id");
06748 cpl_table_erase_column(slits, "xpseudo");
06749 cpl_table_erase_column(slits, "ypseudo");
06750 positions = cpl_table_duplicate(slits);
06751 cpl_table_erase_column(slits, "xcenter");
06752 cpl_table_erase_column(slits, "ycenter");
06753 cpl_msg_warning(func, "(the failure could be caused "
06754 "by a mask with regularly located slits)");
06755 return NULL;
06756 }
06757 }
06758 else {
06759 cpl_msg_info(func, "Preliminarily identified slits: %d out of %d "
06760 "candidates (%d expected)", found_slits, nslits,
06761 nmaskslits);
06762 }
06763
06764
06765
06766
06767
06768
06769
06770
06771 positions = cpl_table_new(found_slits);
06772 cpl_table_new_column(positions, "slit_id", CPL_TYPE_INT);
06773 cpl_table_new_column(positions, "xtop", CPL_TYPE_DOUBLE);
06774 cpl_table_new_column(positions, "ytop", CPL_TYPE_DOUBLE);
06775 cpl_table_new_column(positions, "xbottom", CPL_TYPE_DOUBLE);
06776 cpl_table_new_column(positions, "ybottom", CPL_TYPE_DOUBLE);
06777 cpl_table_new_column(positions, "xcenter", CPL_TYPE_DOUBLE);
06778 cpl_table_new_column(positions, "ycenter", CPL_TYPE_DOUBLE);
06779 cpl_table_new_column(positions, "xmtop", CPL_TYPE_DOUBLE);
06780 cpl_table_new_column(positions, "ymtop", CPL_TYPE_DOUBLE);
06781 cpl_table_new_column(positions, "xmbottom", CPL_TYPE_DOUBLE);
06782 cpl_table_new_column(positions, "ymbottom", CPL_TYPE_DOUBLE);
06783 cpl_table_new_column(positions, "xmcenter", CPL_TYPE_DOUBLE);
06784 cpl_table_new_column(positions, "ymcenter", CPL_TYPE_DOUBLE);
06785 cpl_table_new_column(positions, "good", CPL_TYPE_INT);
06786 cpl_table_fill_column_window_int(positions, "good", 0, found_slits, 0);
06787
06788 slit_id = cpl_table_get_data_int (slits, "slit_id");
06789 xtop = cpl_table_get_data_double(slits, "xtop");
06790 ytop = cpl_table_get_data_double(slits, "ytop");
06791 xbottom = cpl_table_get_data_double(slits, "xbottom");
06792 ybottom = cpl_table_get_data_double(slits, "ybottom");
06793 xcenter = cpl_table_get_data_double(slits, "xcenter");
06794 ycenter = cpl_table_get_data_double(slits, "ycenter");
06795
06796 mslit_id = cpl_table_get_data_int (maskslits, "slit_id");
06797 xmtop = cpl_table_get_data_double(maskslits, "xtop");
06798 ymtop = cpl_table_get_data_double(maskslits, "ytop");
06799 xmbottom = cpl_table_get_data_double(maskslits, "xbottom");
06800 ymbottom = cpl_table_get_data_double(maskslits, "ybottom");
06801 xmcenter = cpl_table_get_data_double(maskslits, "xcenter");
06802 ymcenter = cpl_table_get_data_double(maskslits, "ycenter");
06803
06804
06805
06806
06807
06808
06809
06810
06811 k = 0;
06812 cpl_table_fill_invalid_int(slits, "slit_id", 0);
06813 for (i = 0; i < nmaskslits; i++) {
06814 for (j = 0; j < nslits; j++) {
06815 if (slit_id[j] == 0)
06816 continue;
06817 if (mslit_id[i] == slit_id[j]) {
06818 cpl_table_set_int (positions, "slit_id", k, slit_id[j]);
06819
06820 cpl_table_set_double(positions, "xtop", k, xtop[j]);
06821 cpl_table_set_double(positions, "ytop", k, ytop[j]);
06822 cpl_table_set_double(positions, "xbottom", k, xbottom[j]);
06823 cpl_table_set_double(positions, "ybottom", k, ybottom[j]);
06824 cpl_table_set_double(positions, "xcenter", k, xcenter[j]);
06825 cpl_table_set_double(positions, "ycenter", k, ycenter[j]);
06826
06827 cpl_table_set_double(positions, "xmtop", k, xmtop[i]);
06828 cpl_table_set_double(positions, "ymtop", k, ymtop[i]);
06829 cpl_table_set_double(positions, "xmbottom", k, xmbottom[i]);
06830 cpl_table_set_double(positions, "ymbottom", k, ymbottom[i]);
06831 cpl_table_set_double(positions, "xmcenter", k, xmcenter[i]);
06832 cpl_table_set_double(positions, "ymcenter", k, ymcenter[i]);
06833
06834 k++;
06835
06836 break;
06837 }
06838 }
06839 }
06840
06841 found_slits = k;
06842
06843 cpl_table_erase_column(slits, "slit_id");
06844 cpl_table_erase_column(slits, "xpseudo");
06845 cpl_table_erase_column(slits, "ypseudo");
06846 cpl_table_erase_column(slits, "xcenter");
06847 cpl_table_erase_column(slits, "ycenter");
06848 cpl_table_erase_column(maskslits, "xpseudo");
06849 cpl_table_erase_column(maskslits, "ypseudo");
06850 cpl_table_erase_column(maskslits, "xcenter");
06851 cpl_table_erase_column(maskslits, "ycenter");
06852
06853
06854
06855
06856
06857
06858
06859
06860
06861 ytop = cpl_table_get_data_double(positions, "ytop");
06862 ybottom = cpl_table_get_data_double(positions, "ybottom");
06863 xcenter = cpl_table_get_data_double(positions, "xcenter");
06864 ycenter = cpl_table_get_data_double(positions, "ycenter");
06865 xmcenter = cpl_table_get_data_double(positions, "xmcenter");
06866 ymcenter = cpl_table_get_data_double(positions, "ymcenter");
06867
06868 scales = cpl_vector_new(found_slits - 1);
06869 dscale = cpl_vector_get_data(scales);
06870 angles = cpl_vector_new(found_slits - 1);
06871 dangle = cpl_vector_get_data(angles);
06872
06873 for (i = 1; i < found_slits; i++) {
06874 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
06875 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
06876 dist2 = (xmcenter[i-1] - xmcenter[i]) * (xmcenter[i-1] - xmcenter[i])
06877 + (ymcenter[i-1] - ymcenter[i]) * (ymcenter[i-1] - ymcenter[i]);
06878 dscale[i-1] = sqrt(dist1/dist2);
06879 dangle[i-1] = atan2(ycenter[i-1] - ycenter[i],
06880 xcenter[i-1] - xcenter[i])
06881 - atan2(ymcenter[i-1] - ymcenter[i],
06882 xmcenter[i-1] - xmcenter[i]);
06883 dangle[i-1] *= 180;
06884 dangle[i-1] /= pi;
06885 }
06886
06887 minscale = cpl_vector_get_min(scales);
06888 scale = cpl_vector_get_median_const(scales);
06889 maxscale = cpl_vector_get_max(scales);
06890
06891 minangle = cpl_vector_get_min(angles);
06892 angle = cpl_vector_get_median_const(angles);
06893 maxangle = cpl_vector_get_max(angles);
06894
06895 cpl_msg_info(func, "Median platescale: %f pixel/mm", scale);
06896 cpl_msg_info(func, "Minmax platescale: %f, %f pixel/mm",
06897 minscale, maxscale);
06898
06899 cpl_msg_info(func, "Median rotation: %f degrees", angle);
06900 cpl_msg_info(func, "Minmax rotation: %f, %f degrees",
06901 minangle, maxangle);
06902
06903 good = cpl_table_get_data_int(positions, "good");
06904
06905 good[0] = good[found_slits - 1] = 1;
06906 for (i = 1; i < found_slits; i++) {
06907 if (fabs((dscale[i-1] - scale)/scale) < 0.10
06908 && fabs(dangle[i-1] - angle) < 2) {
06909 good[i-1]++;
06910 good[i]++;
06911 }
06912 }
06913
06914 for (i = 0; i < found_slits; i++) {
06915 if (good[i] < 2)
06916 good[i] = 0;
06917 else
06918 good[i] = 1;
06919 }
06920
06921
06922
06923
06924
06925
06926
06927
06928
06929
06930
06931
06932
06933
06934
06935
06936
06937
06938
06939
06940
06941
06942
06943
06944
06945
06946
06947
06948
06949
06950
06951
06952
06953
06954 cpl_vector_delete(scales);
06955 cpl_vector_delete(angles);
06956
06957 cpl_table_and_selected_int(positions, "good", CPL_EQUAL_TO, 0);
06958 cpl_table_erase_selected(positions);
06959 cpl_table_erase_column(positions, "good");
06960 found_slits = cpl_table_get_nrow(positions);
06961
06962 if (found_slits < 4) {
06963
06964
06965
06966
06967
06968
06969
06970 cpl_msg_warning(func, "Too few safely identified slits: %d out of %d "
06971 "candidates (%d expected). Process will continue "
06972 "using the detected CCD slits positions", found_slits,
06973 nslits, nmaskslits);
06974 cpl_table_delete(positions);
06975 return NULL;
06976 }
06977 else {
06978 cpl_msg_info(func, "Safely identified slits: %d out of %d "
06979 "candidates\n(%d expected)", found_slits, nslits,
06980 nmaskslits);
06981 }
06982
06983
06984
06985
06986
06987
06988
06989
06990 xpos = cpl_vector_wrap(found_slits,
06991 cpl_table_get_data_double(positions, "xcenter"));
06992 ypos = cpl_vector_wrap(found_slits,
06993 cpl_table_get_data_double(positions, "ycenter"));
06994 xmpos = cpl_vector_wrap(found_slits,
06995 cpl_table_get_data_double(positions, "xmcenter"));
06996 ympos = cpl_vector_wrap(found_slits,
06997 cpl_table_get_data_double(positions, "ymcenter"));
06998 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
06999
07000 if (found_slits < 10)
07001 degree = 1;
07002 else
07003 degree = 2;
07004
07005 xpoly = cpl_polynomial_fit_2d_create(mpos, xpos, degree, &xmse);
07006 if (xpoly != NULL)
07007 ypoly = cpl_polynomial_fit_2d_create(mpos, ypos, degree, &ymse);
07008 cpl_bivector_unwrap_vectors(mpos);
07009 cpl_vector_unwrap(xpos);
07010 cpl_vector_unwrap(ypos);
07011 cpl_vector_unwrap(xmpos);
07012 cpl_vector_unwrap(ympos);
07013 if (ypoly == NULL) {
07014 if (found_slits == nmaskslits) {
07015 cpl_msg_warning(func, "Fit failure: the accuracy of the "
07016 "identified slits positions is not improved.");
07017
07018
07019
07020
07021
07022
07023
07024
07025
07026 } else {
07027 cpl_msg_info(func, "Fit failure: not all slits have been "
07028 "identified. Process will continue using "
07029 "the detected CCD slits positions");
07030 }
07031
07032 cpl_polynomial_delete(xpoly);
07033 return positions;
07034 }
07035
07036 cpl_msg_info(func, "Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
07037 sqrt(xmse), sqrt(ymse));
07038
07039 if (global) {
07040 write_global_distortion(global, 0, xpoly);
07041 write_global_distortion(global, 7, ypoly);
07042 }
07043
07044
07045
07046
07047
07048
07049 cpl_table_delete(positions);
07050
07051 positions = cpl_table_duplicate(maskslits);
07052 cpl_table_duplicate_column(positions, "xmtop", positions, "xtop");
07053 cpl_table_duplicate_column(positions, "ymtop", positions, "ytop");
07054 cpl_table_duplicate_column(positions, "xmbottom", positions, "xbottom");
07055 cpl_table_duplicate_column(positions, "ymbottom", positions, "ybottom");
07056
07057 point = cpl_vector_new(2);
07058 dpoint = cpl_vector_get_data(point);
07059
07060 for (i = 0; i < nmaskslits; i++) {
07061 dpoint[0] = cpl_table_get_double(positions, "xmtop", i, NULL);
07062 dpoint[1] = cpl_table_get_double(positions, "ymtop", i, NULL);
07063 cpl_table_set_double(positions, "xtop", i,
07064 cpl_polynomial_eval(xpoly, point));
07065 cpl_table_set_double(positions, "ytop", i,
07066 cpl_polynomial_eval(ypoly, point));
07067 dpoint[0] = cpl_table_get_double(positions, "xmbottom", i, NULL);
07068 dpoint[1] = cpl_table_get_double(positions, "ymbottom", i, NULL);
07069 cpl_table_set_double(positions, "xbottom", i,
07070 cpl_polynomial_eval(xpoly, point));
07071 cpl_table_set_double(positions, "ybottom", i,
07072 cpl_polynomial_eval(ypoly, point));
07073 }
07074
07075 cpl_vector_delete(point);
07076 cpl_polynomial_delete(xpoly);
07077 cpl_polynomial_delete(ypoly);
07078
07079 cpl_table_erase_column(positions, "xmtop");
07080 cpl_table_erase_column(positions, "ymtop");
07081 cpl_table_erase_column(positions, "xmbottom");
07082 cpl_table_erase_column(positions, "ymbottom");
07083
07084 if (nmaskslits > nslits)
07085 cpl_msg_info(func, "Finally identified slits: %d out of %d expected\n"
07086 "(%d recovered)", nmaskslits, nmaskslits, nmaskslits - nslits);
07087 else if (nmaskslits < nslits)
07088 cpl_msg_info(func, "Finally identified slits: %d out of %d expected\n"
07089 "(%d rejected)", nmaskslits, nmaskslits, nslits - nmaskslits);
07090 else
07091 cpl_msg_info(func, "Finally identified slits: %d out of %d expected",
07092 nmaskslits, nmaskslits);
07093
07094 return positions;
07095 }
07096
07097
07139 cpl_table *mos_trace_flat(cpl_image *flat, cpl_table *slits, double reference,
07140 double blue, double red, double dispersion)
07141 {
07142
07143 const char *func = "mos_trace_flat";
07144
07145 cpl_image *gradient;
07146 cpl_image *sgradient;
07147 float *dgradient;
07148 float level = 500;
07149 cpl_vector *row;
07150 cpl_vector *srow;
07151 cpl_vector **peaks;
07152 double *peak;
07153 int *slit_id;
07154 float *g;
07155 double *r;
07156 double *xtop;
07157 double *ytop;
07158 double *xbottom;
07159 double *ybottom;
07160 double min, dist;
07161 double sradius;
07162 double tolerance;
07163 double start_y, prev_y;
07164 int minpos;
07165 int nslits;
07166 int nrows;
07167 int step = 10;
07168 int filtbox = 15;
07169 int nx, ny, npix;
07170 int pos, ypos;
07171 int npeaks;
07172 int pixel_above, pixel_below;
07173 int i, j, k, l;
07174 char trace_id[MAX_COLNAME];
07175
07176 cpl_table *traces;
07177
07178
07179 if (flat == NULL || slits == NULL) {
07180 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07181 return NULL;
07182 }
07183
07184 if (dispersion <= 0.0) {
07185 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07186 return NULL;
07187 }
07188
07189 if (red - blue < dispersion) {
07190 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07191 return NULL;
07192 }
07193
07194
07195
07196
07197
07198
07199 nslits = cpl_table_get_nrow(slits);
07200 if (1 != cpl_table_has_column(slits, "slit_id")) {
07201 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
07202 for (i = 0; i < nslits; i++)
07203 cpl_table_set_int(slits, "slit_id", i, -(i+1));
07204 }
07205
07206 slit_id = cpl_table_get_data_int(slits, "slit_id");
07207
07208 nx = cpl_image_get_size_x(flat);
07209 ny = cpl_image_get_size_y(flat);
07210 npix = nx * ny;
07211
07212 gradient = cpl_image_duplicate(flat);
07213 dgradient = cpl_image_get_data_float(gradient);
07214
07215 for (i = 0; i < ny - 1; i++) {
07216 k = i * nx;
07217 for (j = 0; j < nx; j++) {
07218 l = k + j;
07219 dgradient[l] = fabs(dgradient[l] - dgradient[l + nx]);
07220 }
07221 }
07222
07223 npix--;
07224 for (j = 0; j < nx; j++)
07225 dgradient[npix - j] = 0.0;
07226
07227 cpl_image_turn(gradient, -1);
07228 nx = cpl_image_get_size_x(gradient);
07229 ny = cpl_image_get_size_y(gradient);
07230 sgradient = mos_image_vertical_median_filter(gradient,
07231 filtbox, 0, ny, 0, step);
07232 cpl_image_delete(gradient);
07233
07234
07235
07236
07237
07238
07239 dgradient = cpl_image_get_data_float(sgradient);
07240
07241 for (i = 1; i <= ny; i += step) {
07242 row = cpl_vector_new_from_image_row(sgradient, i);
07243 srow = cpl_vector_filter_median_create(row, filtbox);
07244 cpl_vector_subtract(row, srow);
07245 cpl_vector_delete(srow);
07246 g = dgradient + (i-1)*nx;
07247 r = cpl_vector_get_data(row);
07248 for (j = 0; j < nx; j++)
07249 g[j] = r[j];
07250 cpl_vector_delete(row);
07251 }
07252
07253
07254
07255
07256
07257
07258
07259 mos_rotate_slits(slits, 1, nx, ny);
07260 xtop = cpl_table_get_data_double(slits, "xtop");
07261 ytop = cpl_table_get_data_double(slits, "ytop");
07262 xbottom = cpl_table_get_data_double(slits, "xbottom");
07263 ybottom = cpl_table_get_data_double(slits, "ybottom");
07264
07265
07266
07267
07268
07269
07270
07271 peaks = cpl_calloc(ny, sizeof(cpl_vector *));
07272
07273 for (i = 0; i < ny; i += step) {
07274 g = dgradient + i*nx;
07275 peaks[i] = mos_peak_candidates(g, nx, level, 1.0);
07276
07277
07278
07279 if (peaks[i])
07280 cpl_vector_subtract_scalar(peaks[i], 0.5);
07281
07282 }
07283
07284 cpl_image_delete(sgradient);
07285
07286
07287
07288
07289
07290
07291
07292
07293
07294 sradius = 5.0;
07295
07296
07297
07298
07299
07300
07301
07302
07303 tolerance = 0.9;
07304
07305
07306
07307
07308
07309
07310 pixel_above = (red - reference) / dispersion;
07311 pixel_below = (reference - blue) / dispersion;
07312
07313
07314
07315
07316
07317
07318 nrows = (ny-1)/step + 1;
07319 traces = cpl_table_new(nrows);
07320 cpl_table_new_column(traces, "x", CPL_TYPE_DOUBLE);
07321 cpl_table_set_column_unit(traces, "x", "pixel");
07322 for (i = 0, j = 0; i < ny; i += step, j++)
07323 cpl_table_set(traces, "x", j, i);
07324
07325 for (i = 0; i < nslits; i++) {
07326
07327
07328
07329
07330
07331 ypos = ytop[i];
07332
07333 if (ypos < 0)
07334 ypos = 0;
07335 if (ypos >= ny)
07336 ypos = ny - 1;
07337
07338 pos = ypos / step;
07339 pos *= step;
07340
07341
07342
07343
07344
07345 if (peaks[pos]) {
07346 peak = cpl_vector_get_data(peaks[pos]);
07347 npeaks = cpl_vector_get_size(peaks[pos]);
07348
07349 min = fabs(peak[0] - xtop[i]);
07350 minpos = 0;
07351 for (j = 1; j < npeaks; j++) {
07352 dist = fabs(peak[j] - xtop[i]);
07353 if (min > dist) {
07354 min = dist;
07355 minpos = j;
07356 }
07357 }
07358 }
07359 else {
07360 npeaks = 0;
07361 }
07362
07363 snprintf(trace_id, MAX_COLNAME, "t%d", slit_id[i]);
07364 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
07365
07366 if (min > sradius || npeaks == 0) {
07367 cpl_msg_warning(func, "Cannot find spectrum edge for "
07368 "top (or left) end of slit %d", slit_id[i]);
07369 }
07370 else {
07371
07372
07373
07374
07375
07376
07377
07378
07379
07380 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
07381 start_y = peak[minpos];
07382
07383
07384
07385
07386
07387 prev_y = start_y;
07388
07389 for (j = pos + step; j < ny; j += step) {
07390 if (j - pos > pixel_above)
07391 break;
07392 if (peaks[j]) {
07393 peak = cpl_vector_get_data(peaks[j]);
07394 npeaks = cpl_vector_get_size(peaks[j]);
07395 min = fabs(peak[0] - prev_y);
07396 minpos = 0;
07397 for (k = 1; k < npeaks; k++) {
07398 dist = fabs(peak[k] - prev_y);
07399 if (min > dist) {
07400 min = dist;
07401 minpos = k;
07402 }
07403 }
07404 if (min < tolerance) {
07405 cpl_table_set(traces, trace_id, j/step,
07406 nx - peak[minpos]);
07407 prev_y = peak[minpos];
07408 }
07409 }
07410 }
07411
07412
07413
07414
07415
07416 prev_y = start_y;
07417
07418 for (j = pos - step; j >= 0; j -= step) {
07419 if (pos - j > pixel_below)
07420 break;
07421 if (peaks[j]) {
07422 peak = cpl_vector_get_data(peaks[j]);
07423 npeaks = cpl_vector_get_size(peaks[j]);
07424 min = fabs(peak[0] - prev_y);
07425 minpos = 0;
07426 for (k = 1; k < npeaks; k++) {
07427 dist = fabs(peak[k] - prev_y);
07428 if (min > dist) {
07429 min = dist;
07430 minpos = k;
07431 }
07432 }
07433 if (min < tolerance) {
07434 cpl_table_set(traces, trace_id, j/step,
07435 nx - peak[minpos]);
07436 prev_y = peak[minpos];
07437 }
07438 }
07439 }
07440 }
07441
07442
07443
07444
07445
07446
07447 if (peaks[pos]) {
07448 peak = cpl_vector_get_data(peaks[pos]);
07449 npeaks = cpl_vector_get_size(peaks[pos]);
07450
07451 min = fabs(peak[0] - xbottom[i]);
07452 minpos = 0;
07453 for (j = 1; j < npeaks; j++) {
07454 dist = fabs(peak[j] - xbottom[i]);
07455 if (min > dist) {
07456 min = dist;
07457 minpos = j;
07458 }
07459 }
07460 }
07461 else {
07462 npeaks = 0;
07463 }
07464
07465 snprintf(trace_id, MAX_COLNAME, "b%d", slit_id[i]);
07466 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
07467
07468 if (min > sradius || npeaks == 0) {
07469 cpl_msg_warning(func, "Cannot find spectrum edge for "
07470 "bottom (or right) end of slit %d", slit_id[i]);
07471 }
07472 else {
07473
07474 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
07475 start_y = peak[minpos];
07476
07477
07478
07479
07480
07481 prev_y = start_y;
07482
07483 for (j = pos + step; j < ny; j += step) {
07484 if (j - pos > pixel_above)
07485 break;
07486 if (peaks[j]) {
07487 peak = cpl_vector_get_data(peaks[j]);
07488 npeaks = cpl_vector_get_size(peaks[j]);
07489 min = fabs(peak[0] - prev_y);
07490 minpos = 0;
07491 for (k = 1; k < npeaks; k++) {
07492 dist = fabs(peak[k] - prev_y);
07493 if (min > dist) {
07494 min = dist;
07495 minpos = k;
07496 }
07497 }
07498 if (min < tolerance) {
07499 cpl_table_set(traces, trace_id, j/step,
07500 nx - peak[minpos]);
07501 prev_y = peak[minpos];
07502 }
07503 }
07504 }
07505
07506
07507
07508
07509
07510 prev_y = start_y;
07511
07512 for (j = pos - step; j >= 0; j -= step) {
07513 if (pos - j > pixel_below)
07514 break;
07515 if (peaks[j]) {
07516 peak = cpl_vector_get_data(peaks[j]);
07517 npeaks = cpl_vector_get_size(peaks[j]);
07518 min = fabs(peak[0] - prev_y);
07519 minpos = 0;
07520 for (k = 1; k < npeaks; k++) {
07521 dist = fabs(peak[k] - prev_y);
07522 if (min > dist) {
07523 min = dist;
07524 minpos = k;
07525 }
07526 }
07527 if (min < tolerance) {
07528 cpl_table_set(traces, trace_id, j/step,
07529 nx - peak[minpos]);
07530 prev_y = peak[minpos];
07531 }
07532 }
07533 }
07534 }
07535
07536 }
07537
07538 for (i = 0; i < ny; i += step)
07539 cpl_vector_delete(peaks[i]);
07540 cpl_free(peaks);
07541
07542
07543
07544
07545
07546 mos_rotate_slits(slits, -1, ny, nx);
07547
07548 return traces;
07549
07550 }
07551
07552
07573 cpl_table *mos_poly_trace(cpl_table *slits, cpl_table *traces, int order)
07574 {
07575 const char *func = "mos_poly_trace";
07576
07577 cpl_table *polytraces;
07578 cpl_table *dummy;
07579 cpl_vector *x;
07580 cpl_vector *trace;
07581 cpl_polynomial *polytrace;
07582 char trace_id[MAX_COLNAME];
07583 char trace_res[MAX_COLNAME];
07584 char trace_mod[MAX_COLNAME];
07585 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
07586
07587 double *xdata;
07588 int *slit_id;
07589 int nslits;
07590 int nrows;
07591 int npoints;
07592 int i, j, k;
07593
07594
07595 if (traces == NULL || slits == NULL) {
07596 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07597 return NULL;
07598 }
07599
07600 if (order > 5) {
07601 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07602 return NULL;
07603 }
07604
07605 nrows = cpl_table_get_nrow(traces);
07606 xdata = cpl_table_get_data_double(traces, "x");
07607 nslits = cpl_table_get_nrow(slits);
07608 slit_id = cpl_table_get_data_int(slits, "slit_id");
07609
07610 polytraces = cpl_table_new(2*nslits);
07611 cpl_table_new_column(polytraces, "slit_id", CPL_TYPE_INT);
07612 for (i = 0; i <= order; i++)
07613 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
07614
07615 for (i = 0; i < nslits; i++) {
07616 for (j = 0; j < 2; j++) {
07617
07618 if (j) {
07619 snprintf(trace_id, MAX_COLNAME, "b%d", slit_id[i]);
07620 snprintf(trace_res, MAX_COLNAME, "b%d_res", slit_id[i]);
07621 snprintf(trace_mod, MAX_COLNAME, "b%d_mod", slit_id[i]);
07622 }
07623 else {
07624 snprintf(trace_id, MAX_COLNAME, "t%d", slit_id[i]);
07625 snprintf(trace_res, MAX_COLNAME, "t%d_res", slit_id[i]);
07626 snprintf(trace_mod, MAX_COLNAME, "t%d_mod", slit_id[i]);
07627 }
07628
07629 cpl_table_set_int(polytraces, "slit_id", 2*i+j, slit_id[i]);
07630
07631
07632
07633
07634
07635
07636 dummy = cpl_table_new(nrows);
07637 cpl_table_duplicate_column(dummy, "x", traces, "x");
07638 cpl_table_duplicate_column(dummy, trace_id, traces, trace_id);
07639 npoints = nrows - cpl_table_count_invalid(dummy, trace_id);
07640 if (npoints < 2 * order) {
07641 cpl_table_delete(dummy);
07642 continue;
07643 }
07644 cpl_table_erase_invalid(dummy);
07645 x = cpl_vector_wrap(npoints,
07646 cpl_table_get_data_double(dummy, "x"));
07647 trace = cpl_vector_wrap(npoints,
07648 cpl_table_get_data_double(dummy, trace_id));
07649 polytrace = cpl_polynomial_fit_1d_create(x, trace, order, NULL);
07650 cpl_vector_unwrap(x);
07651 cpl_vector_unwrap(trace);
07652 cpl_table_delete(dummy);
07653
07654
07655
07656
07657
07658
07659
07660 k = 2;
07661 if (cpl_polynomial_get_coeff(polytrace, &k) > 1.E-5) {
07662 cpl_polynomial_delete(polytrace);
07663 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
07664 cpl_table_duplicate_column(traces, trace_res, traces,
07665 trace_mod);
07666 if (j)
07667 cpl_msg_warning(func, "Exclude bad curvature solution "
07668 "for bottom (right) edge of slit %d", slit_id[i]);
07669 else
07670 cpl_msg_warning(func, "Exclude bad curvature solution "
07671 "for top (left) edge of slit %d", slit_id[i]);
07672 continue;
07673 }
07674
07675
07676
07677
07678
07679
07680 for (k = 0; k <= order; k++)
07681 cpl_table_set_double(polytraces, clab[k], 2*i+j,
07682 cpl_polynomial_get_coeff(polytrace, &k));
07683
07684
07685
07686
07687
07688 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
07689 cpl_table_set_column_unit(traces, trace_mod, "pixel");
07690
07691 for (k = 0; k < nrows; k++) {
07692 cpl_table_set_double(traces, trace_mod, k,
07693 cpl_polynomial_eval_1d(polytrace, xdata[k], NULL));
07694 }
07695
07696 cpl_polynomial_delete(polytrace);
07697
07698 cpl_table_duplicate_column(traces, trace_res, traces, trace_mod);
07699 cpl_table_subtract_columns(traces, trace_res, trace_id);
07700 cpl_table_multiply_scalar(traces, trace_res, -1.0);
07701
07702 }
07703 }
07704
07705 return polytraces;
07706
07707 }
07708
07709
07733 cpl_error_code mos_global_trace(cpl_table *slits, cpl_table *polytraces,
07734 int mode)
07735 {
07736 const char *func = "mos_global_trace";
07737
07738 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
07739
07740 cpl_table *table;
07741 cpl_vector *c0;
07742 cpl_vector *cn;
07743 cpl_bivector *list;
07744
07745
07746
07747
07748 double *offset;
07749 double rms, q, m;
07750
07751 int order, nrows, nslits;
07752 int i, j;
07753
07754
07755 if (polytraces == NULL) {
07756 cpl_msg_error(func, "Missing spectral curvature table");
07757 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07758 }
07759
07760 if (slits == NULL) {
07761 cpl_msg_error(func, "Missing slits positions table");
07762 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07763 }
07764
07765 nslits = cpl_table_get_nrow(slits);
07766
07767 table = cpl_table_duplicate(polytraces);
07768 cpl_table_erase_invalid(table);
07769
07770 nrows = cpl_table_get_nrow(table);
07771
07772 if (nrows < 4) {
07773 cpl_msg_warning(func, "Too few successful spectral curvature tracings "
07774 "(%d): the determination of a global curvature model "
07775 "failed", nrows);
07776 return CPL_ERROR_NONE;
07777 }
07778
07779 order = cpl_table_get_ncol(polytraces) - 2;
07780
07781 for (i = 0; i <= order; i++) {
07782 if (!cpl_table_has_column(table, clab[i])) {
07783 cpl_msg_error(func, "Wrong spectral curvature table");
07784 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07785 }
07786 }
07787
07788
07789
07790
07791
07792
07793 for (i = 0; i < nslits; i++) {
07794 if (!cpl_table_is_valid(polytraces, clab[0], 2*i)) {
07795 cpl_table_set_double(polytraces, clab[0], 2*i,
07796 cpl_table_get_double(slits, "ytop", i, NULL));
07797 }
07798 if (!cpl_table_is_valid(polytraces, clab[0], 2*i+1)) {
07799 cpl_table_set_double(polytraces, clab[0], 2*i+1,
07800 cpl_table_get_double(slits, "ybottom", i, NULL));
07801 }
07802 }
07803
07804 offset = cpl_table_get_data_double(polytraces, clab[0]);
07805
07806
07807
07808
07809
07810
07811 c0 = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[0]));
07812
07813 for (i = 1; i <= order; i++) {
07814 cn = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[i]));
07815 list = cpl_bivector_wrap_vectors(c0, cn);
07816 robustLinearFit(list, &q, &m, &rms);
07817
07818
07819
07820 for (j = 0; j < 2*nslits; j++) {
07821 if (mode == 1)
07822 if (cpl_table_is_valid(polytraces, clab[i], j))
07823 continue;
07824 cpl_table_set_double(polytraces, clab[i], j, offset[j]*m + q);
07825
07826
07827
07828
07829 }
07830 cpl_bivector_unwrap_vectors(list);
07831
07832
07833
07834 cpl_vector_unwrap(cn);
07835 }
07836
07837 cpl_vector_unwrap(c0);
07838 cpl_table_delete(table);
07839
07840 return CPL_ERROR_NONE;
07841
07842 }
07843
07844
07914 cpl_image *mos_spatial_calibration(cpl_image *spectra, cpl_table *slits,
07915 cpl_table *polytraces, double reference,
07916 double blue, double red, double dispersion,
07917 int flux, cpl_image *calibration)
07918 {
07919 const char *func = "mos_spatial_calibration";
07920
07921 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
07922
07923 cpl_polynomial *polytop;
07924 cpl_polynomial *polybot;
07925 cpl_image **exslit;
07926 cpl_image *resampled;
07927 float *data;
07928 float *sdata;
07929 float *xdata;
07930 double vtop, vbot, value;
07931 double top, bot;
07932 double coeff;
07933 double ytop, ybot;
07934 double ypos, yfra;
07935 double factor;
07936 int yint, ysize, yprev;
07937 int nslits;
07938 int npseudo;
07939 int *slit_id;
07940 int *length;
07941 int nx, ny;
07942 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
07943 int missing_top, missing_bot;
07944 int null;
07945 int order;
07946 int i, j, k;
07947
07948 int create_position = 1;
07949
07950
07951 if (spectra == NULL || slits == NULL || polytraces == NULL) {
07952 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07953 return NULL;
07954 }
07955
07956 if (dispersion <= 0.0) {
07957 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07958 return NULL;
07959 }
07960
07961 if (red - blue < dispersion) {
07962 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07963 return NULL;
07964 }
07965
07966 nx = cpl_image_get_size_x(spectra);
07967 ny = cpl_image_get_size_y(spectra);
07968 sdata = cpl_image_get_data(spectra);
07969 if (calibration)
07970 data = cpl_image_get_data(calibration);
07971
07972 if (cpl_table_has_column(slits, "position"))
07973 create_position = 0;
07974
07975 if (create_position) {
07976 cpl_table_new_column(slits, "position", CPL_TYPE_INT);
07977 cpl_table_new_column(slits, "length", CPL_TYPE_INT);
07978 cpl_table_set_column_unit(slits, "position", "pixel");
07979 cpl_table_set_column_unit(slits, "length", "pixel");
07980 }
07981 else
07982 length = cpl_table_get_data_int(slits, "length");
07983
07984 nslits = cpl_table_get_nrow(slits);
07985 slit_id = cpl_table_get_data_int(slits, "slit_id");
07986 order = cpl_table_get_ncol(polytraces) - 2;
07987
07988
07989
07990
07991
07992
07993 pixel_above = (red - reference) / dispersion;
07994 pixel_below = (reference - blue) / dispersion;
07995
07996 exslit = cpl_calloc(nslits, sizeof(cpl_image *));
07997
07998 for (i = 0; i < nslits; i++) {
07999
08000 if (create_position == 0)
08001 if (length[i] == 0)
08002 continue;
08003
08004
08005
08006
08007
08008
08009
08010
08011
08012
08013
08014
08015 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
08016
08017 start_pixel = refpixel - pixel_below;
08018 if (start_pixel < 0)
08019 start_pixel = 0;
08020
08021 end_pixel = refpixel + pixel_above;
08022 if (end_pixel > nx)
08023 end_pixel = nx;
08024
08025
08026
08027
08028
08029
08030 missing_top = 0;
08031 polytop = cpl_polynomial_new(1);
08032 for (k = 0; k <= order; k++) {
08033 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
08034 if (null) {
08035 cpl_polynomial_delete(polytop);
08036 missing_top = 1;
08037 break;
08038 }
08039 cpl_polynomial_set_coeff(polytop, &k, coeff);
08040 }
08041
08042 missing_bot = 0;
08043 polybot = cpl_polynomial_new(1);
08044 for (k = 0; k <= order; k++) {
08045 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
08046 if (null) {
08047 cpl_polynomial_delete(polybot);
08048 missing_bot = 1;
08049 break;
08050 }
08051 cpl_polynomial_set_coeff(polybot, &k, coeff);
08052 }
08053
08054 if (missing_top && missing_bot) {
08055 cpl_msg_warning(func, "Spatial calibration, slit %d was not "
08056 "traced: no extraction!",
08057 slit_id[i]);
08058 continue;
08059 }
08060
08061
08062
08063
08064
08065
08066
08067 if (missing_top) {
08068 cpl_msg_warning(func, "Upper edge of slit %d was not traced: "
08069 "the spectral curvature of the lower edge "
08070 "is used instead.", slit_id[i]);
08071 polytop = cpl_polynomial_duplicate(polybot);
08072 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
08073 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
08074 k = 0;
08075 coeff = cpl_polynomial_get_coeff(polybot, &k);
08076 coeff += ytop - ybot;
08077 cpl_polynomial_set_coeff(polytop, &k, coeff);
08078 }
08079
08080 if (missing_bot) {
08081 cpl_msg_warning(func, "Lower edge of slit %d was not traced: "
08082 "the spectral curvature of the upper edge "
08083 "is used instead.", slit_id[i]);
08084 polybot = cpl_polynomial_duplicate(polytop);
08085 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
08086 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
08087 k = 0;
08088 coeff = cpl_polynomial_get_coeff(polytop, &k);
08089 coeff -= ytop - ybot;
08090 cpl_polynomial_set_coeff(polybot, &k, coeff);
08091 }
08092
08093
08094
08095
08096
08097 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
08098 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
08099 npseudo = ceil(top-bot) + 1;
08100
08101 if (npseudo < 1) {
08102 cpl_polynomial_delete(polytop);
08103 cpl_polynomial_delete(polybot);
08104 cpl_msg_warning(func, "Slit %d was badly traced: no extraction!",
08105 slit_id[i]);
08106 continue;
08107 }
08108
08109 exslit[i] = cpl_image_new(nx, npseudo+1, CPL_TYPE_FLOAT);
08110 xdata = cpl_image_get_data(exslit[i]);
08111
08112
08113
08114
08115
08116 for (j = start_pixel; j < end_pixel; j++) {
08117 top = cpl_polynomial_eval_1d(polytop, j, NULL);
08118 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
08119 factor = (top-bot)/npseudo;
08120 for (k = 0; k <= npseudo; k++) {
08121 ypos = top - k*factor;
08122 yint = ypos;
08123 yfra = ypos - yint;
08124 if (yint >= 0 && yint < ny-1) {
08125 vtop = sdata[j + nx*yint];
08126 vbot = sdata[j + nx*(yint+1)];
08127 value = vtop*(1-yfra) + vbot*yfra;
08128 if (flux)
08129 value *= factor;
08130 xdata[j + nx*(npseudo-k)] = value;
08131 if (calibration) {
08132 data[j + nx*yint] = (top-yint)/factor;
08133 if (k) {
08134
08135
08136
08137
08138
08139
08140
08141 if (yprev - yint > 1) {
08142 data[j + nx*(yint+1)] = (top-yint-1)/factor;
08143 }
08144 }
08145 }
08146 }
08147 yprev = yint;
08148 }
08149 }
08150 cpl_polynomial_delete(polytop);
08151 cpl_polynomial_delete(polybot);
08152 }
08153
08154
08155
08156
08157
08158 ysize = 0;
08159 for (i = 0; i < nslits; i++)
08160 if (exslit[i])
08161 ysize += cpl_image_get_size_y(exslit[i]);
08162
08163 resampled = cpl_image_new(nx, ysize, CPL_TYPE_FLOAT);
08164
08165 yint = -1;
08166 for (i = 0; i < nslits; i++) {
08167 if (exslit[i]) {
08168 yint += cpl_image_get_size_y(exslit[i]);
08169 cpl_image_copy(resampled, exslit[i], 1, ysize - yint);
08170 if (create_position) {
08171 cpl_table_set_int(slits, "position", i, ysize - yint - 1);
08172 cpl_table_set_int(slits, "length", i,
08173 cpl_image_get_size_y(exslit[i]));
08174 }
08175 cpl_image_delete(exslit[i]);
08176 }
08177 else if (create_position) {
08178 cpl_table_set_int(slits, "position", i, -1);
08179 cpl_table_set_int(slits, "length", i, 0);
08180 }
08181 }
08182
08183
08184
08185
08186
08187
08188
08189
08190
08191
08192
08193
08194
08195
08196
08197
08198
08199 cpl_free(exslit);
08200
08201 return resampled;
08202
08203 }
08204
08205
08312 cpl_image *mos_wavelength_calibration_final(cpl_image *image, cpl_table *slits,
08313 cpl_vector *lines,
08314 double dispersion, float level,
08315 int sradius, int order,
08316 double reject, double refwave,
08317 double *wavestart, double *waveend,
08318 int *nlines, double *error,
08319 cpl_table *idscoeff,
08320 cpl_image *calibration,
08321 cpl_image *residuals,
08322 cpl_table *restable)
08323 {
08324
08325 const char *func = "mos_wavelength_calibration_final";
08326
08327 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
08328
08329
08330 double tolerance = 20.0;
08331 int step = 10;
08332
08333 char name[MAX_COLNAME];
08334
08335 cpl_image *resampled;
08336 cpl_bivector *output;
08337 cpl_vector *wavel;
08338 cpl_vector *peaks;
08339 cpl_polynomial *ids;
08340 cpl_polynomial *lin;
08341 cpl_polynomial *fguess;
08342 cpl_table *coeff;
08343 double ids_err;
08344 double max_disp, min_disp;
08345 double *line;
08346 double firstLambda, lastLambda, lambda;
08347 double wave, pixe, value;
08348 double c;
08349 float *sdata;
08350 float *rdata;
08351 float *idata;
08352 float *ddata;
08353 float v1, v2, vi;
08354 float fpixel;
08355 int *length;
08356 int pixstart, pixend;
08357 int row_top, row_bot;
08358 int extrapolation;
08359 int nref;
08360 int nslits;
08361 int nfits;
08362 int nl, nx, ny, pixel;
08363 int countLines, usedLines;
08364 int uorder;
08365 int missing;
08366 int null;
08367 int width, uradius;
08368 int i, j, k, s;
08369
08370
08371 if (dispersion == 0.0) {
08372 cpl_msg_error(func, "The expected dispersion (A/pixel) must be given");
08373 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08374 return NULL;
08375 }
08376
08377 if (dispersion < 0.0) {
08378 cpl_msg_error(func, "The expected dispersion must be positive");
08379 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08380 return NULL;
08381 }
08382
08383 if (idscoeff == NULL) {
08384 cpl_msg_error(func, "A preallocated IDS coeff table must be given");
08385 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08386 return NULL;
08387 }
08388
08389 max_disp = dispersion + dispersion * tolerance / 100;
08390 min_disp = dispersion - dispersion * tolerance / 100;
08391
08392 if (order < 1) {
08393 cpl_msg_error(func, "The order of the fitting polynomial "
08394 "must be at least 1");
08395 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08396 return NULL;
08397 }
08398
08399 if (image == NULL || lines == NULL) {
08400 cpl_msg_error(func, "Both spectral exposure and reference line "
08401 "catalog are required in input");
08402 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08403 return NULL;
08404 }
08405
08406 nx = cpl_image_get_size_x(image);
08407 ny = cpl_image_get_size_y(image);
08408 sdata = cpl_image_get_data_float(image);
08409
08410 nref = cpl_vector_get_size(lines);
08411 line = cpl_vector_get_data(lines);
08412
08413 if (*wavestart < 1.0 && *waveend < 1.0) {
08414 firstLambda = line[0];
08415 lastLambda = line[nref-1];
08416 extrapolation = (lastLambda - firstLambda) / 10;
08417 firstLambda -= extrapolation;
08418 lastLambda += extrapolation;
08419 *wavestart = firstLambda;
08420 *waveend = lastLambda;
08421 }
08422 else {
08423 firstLambda = *wavestart;
08424 lastLambda = *waveend;
08425 }
08426
08427 nl = (lastLambda - firstLambda) / dispersion;
08428 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
08429 rdata = cpl_image_get_data_float(resampled);
08430
08431
08432
08433
08434
08435 for (j = 0; j <= order; j++)
08436 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
08437
08438 if (calibration)
08439 idata = cpl_image_get_data_float(calibration);
08440
08441 if (residuals)
08442 ddata = cpl_image_get_data_float(residuals);
08443
08444 if (restable) {
08445 cpl_table_set_size(restable, nref);
08446 cpl_table_new_column(restable, "wavelength", CPL_TYPE_DOUBLE);
08447 cpl_table_copy_data_double(restable, "wavelength", line);
08448 for (i = 0; i < ny; i += step) {
08449 snprintf(name, MAX_COLNAME, "r%d", i);
08450 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
08451 snprintf(name, MAX_COLNAME, "d%d", i);
08452 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
08453 snprintf(name, MAX_COLNAME, "p%d", i);
08454 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
08455 }
08456 }
08457
08458
08459
08460
08461
08462
08463 nslits = cpl_table_get_nrow(slits);
08464 length = cpl_table_get_data_int(slits, "length");
08465
08466 row_top = ny;
08467 for (s = 0; s < nslits; s++) {
08468
08469 if (length[s] == 0)
08470 continue;
08471
08472
08473
08474
08475
08476
08477 row_bot = cpl_table_get_int(slits, "position", s, NULL);
08478
08479 if (sradius > 0) {
08480
08481
08482
08483
08484
08485
08486
08487
08488
08489 coeff = cpl_table_new(row_top - row_bot);
08490 for (j = 0; j <= order; j++)
08491 cpl_table_new_column(coeff, clab[j], CPL_TYPE_DOUBLE);
08492 }
08493
08494
08495
08496
08497
08498
08499 for (i = row_bot; i < row_top; i++) {
08500 width = mos_lines_width(sdata + i*nx, nx);
08501 if (width < 5)
08502 width = 5;
08503 peaks = mos_peak_candidates(sdata + i*nx, nx, level, width);
08504 if (peaks) {
08505 peaks = mos_refine_peaks(sdata + i*nx, nx, peaks, width);
08506 }
08507 if (peaks) {
08508 output = mos_identify_peaks(peaks, lines,
08509 min_disp, max_disp, 0.05, -1);
08510 if (output) {
08511 countLines = cpl_bivector_get_size(output);
08512 if (countLines < 4) {
08513 cpl_bivector_delete(output);
08514 cpl_vector_delete(peaks);
08515 if (nlines)
08516 nlines[i] = 0;
08517 if (error)
08518 error[i] = 0.0;
08519 continue;
08520 }
08521
08522
08523
08524
08525
08526 wavel = cpl_bivector_get_y(output);
08527 cpl_vector_subtract_scalar(wavel, refwave);
08528
08529 uorder = countLines / 2 - 1;
08530 if (uorder > order)
08531 uorder = order;
08532
08533 ids = mos_poly_wav2pix(output, uorder, reject,
08534 2 * (uorder + 1), &usedLines,
08535 &ids_err);
08536
08537 if (ids == NULL) {
08538 cpl_bivector_delete(output);
08539 cpl_vector_delete(peaks);
08540 if (nlines)
08541 nlines[i] = 0;
08542 if (error)
08543 error[i] = 0.0;
08544 cpl_error_reset();
08545 continue;
08546 }
08547
08548 if (sradius > 0) {
08549 for (k = 0; k <= order; k++) {
08550 if (k > uorder) {
08551 cpl_table_set_double(coeff, clab[k],
08552 i - row_bot, 0.0);
08553 }
08554 else {
08555 cpl_table_set_double(coeff, clab[k],
08556 i - row_bot, cpl_polynomial_get_coeff(ids, &k));
08557 }
08558 }
08559 }
08560
08561 if (calibration) {
08562 pixstart = cpl_polynomial_eval_1d(ids,
08563 cpl_bivector_get_y_data(output)[0],
08564 NULL);
08565 pixend = cpl_polynomial_eval_1d(ids,
08566 cpl_bivector_get_y_data(output)[countLines-1],
08567 NULL);
08568 extrapolation = (pixend - pixstart) / 5;
08569 pixstart -= extrapolation;
08570 pixend += extrapolation;
08571 if (pixstart < 0)
08572 pixstart = 0;
08573 if (pixend > nx)
08574 pixend = nx;
08575
08576 for (j = pixstart; j < pixend; j++) {
08577 (idata + i*nx)[j] = mos_eval_dds(ids,
08578 firstLambda, lastLambda, refwave, j);
08579 }
08580 }
08581
08582
08583
08584
08585
08586 if (residuals || (restable && !(i%step))) {
08587 if (restable && !(i%step)) {
08588 lin = cpl_polynomial_new(1);
08589 for (k = 0; k < 2; k++)
08590 cpl_polynomial_set_coeff(lin, &k,
08591 cpl_polynomial_get_coeff(ids, &k));
08592 }
08593 for (j = 0; j < countLines; j++) {
08594 pixe = cpl_bivector_get_x_data(output)[j];
08595 wave = cpl_bivector_get_y_data(output)[j];
08596 value = pixe
08597 - cpl_polynomial_eval_1d(ids, wave, NULL);
08598 if (residuals) {
08599 pixel = pixe + 0.5;
08600 (ddata + i*nx)[pixel] = value;
08601 }
08602 if (restable && !(i%step)) {
08603 for (k = 0; k < nref; k++) {
08604 if (fabs(line[k]-refwave-wave) < 0.1) {
08605 snprintf(name, MAX_COLNAME,
08606 "r%d", i);
08607 cpl_table_set_double(restable, name,
08608 k, value);
08609 value = pixe
08610 - cpl_polynomial_eval_1d(lin,
08611 wave, NULL);
08612 snprintf(name, MAX_COLNAME,
08613 "d%d", i);
08614 cpl_table_set_double(restable, name,
08615 k, value);
08616 snprintf(name, MAX_COLNAME,
08617 "p%d", i);
08618 cpl_table_set_double(restable, name,
08619 k, pixe);
08620 break;
08621 }
08622 }
08623 }
08624 }
08625 if (restable && !(i%step)) {
08626 cpl_polynomial_delete(lin);
08627 }
08628
08629
08630
08631
08632
08633
08634
08635
08636
08637
08638
08639 }
08640
08641
08642
08643
08644
08645
08646
08647
08648 if (nlines)
08649 nlines[i] = usedLines;
08650 if (error)
08651 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
08652
08653 for (k = 0; k <= order; k++) {
08654 if (k > uorder) {
08655 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
08656 }
08657 else {
08658 cpl_table_set_double(idscoeff, clab[k], i,
08659 cpl_polynomial_get_coeff(ids, &k));
08660 }
08661 }
08662
08663 cpl_polynomial_delete(ids);
08664 cpl_bivector_delete(output);
08665 }
08666 cpl_vector_delete(peaks);
08667 }
08668 }
08669
08670
08671 if (sradius > 0) {
08672
08673
08674
08675
08676
08677 nfits = row_top - row_bot - cpl_table_count_invalid(coeff, clab[0]);
08678
08679 if (nfits) {
08680
08681
08682
08683
08684
08685 fguess = cpl_polynomial_new(1);
08686
08687 for (k = 0; k <= order; k++) {
08688 c = cpl_table_get_column_median(coeff, clab[k]);
08689 cpl_polynomial_set_coeff(fguess, &k, c);
08690 }
08691
08692 for (i = row_bot; i < row_top; i++) {
08693
08694
08695
08696
08697
08698 width = mos_lines_width(sdata + i*nx, nx);
08699 if (width > sradius) {
08700 uradius = width;
08701 }
08702 else {
08703 uradius = sradius;
08704 }
08705
08706 output = mos_find_peaks(sdata + i*nx, nx, lines,
08707 fguess, refwave, uradius);
08708
08709 if (output == NULL) {
08710 cpl_error_reset();
08711 continue;
08712 }
08713
08714 countLines = cpl_bivector_get_size(output);
08715
08716 if (countLines < 4) {
08717 cpl_bivector_delete(output);
08718 continue;
08719 }
08720
08721
08722
08723
08724
08725 wavel = cpl_bivector_get_y(output);
08726 cpl_vector_subtract_scalar(wavel, refwave);
08727
08728 uorder = countLines / 2 - 1;
08729 if (uorder > order)
08730 uorder = order;
08731
08732 ids = mos_poly_wav2pix(output, uorder, reject,
08733 2 * (uorder + 1), &usedLines,
08734 &ids_err);
08735
08736 if (ids == NULL) {
08737 cpl_error_reset();
08738 cpl_bivector_delete(output);
08739 continue;
08740 }
08741
08742 if (nlines)
08743 nlines[i] = usedLines;
08744 if (error)
08745 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
08746
08747 if (calibration) {
08748 pixstart = cpl_polynomial_eval_1d(ids,
08749 cpl_bivector_get_y_data(output)[0],
08750 NULL);
08751 pixend = cpl_polynomial_eval_1d(ids,
08752 cpl_bivector_get_y_data(output)[countLines-1],
08753 NULL);
08754 extrapolation = (pixend - pixstart) / 5;
08755 pixstart -= extrapolation;
08756 pixend += extrapolation;
08757 if (pixstart < 0)
08758 pixstart = 0;
08759 if (pixend > nx)
08760 pixend = nx;
08761
08762 for (j = pixstart; j < pixend; j++) {
08763 (idata + i*nx)[j] = mos_eval_dds(ids,
08764 firstLambda, lastLambda, refwave, j);
08765 }
08766 }
08767
08768
08769
08770
08771
08772 if (residuals || (restable && !(i%step))) {
08773 if (restable && !(i%step)) {
08774 lin = cpl_polynomial_new(1);
08775 for (k = 0; k < 2; k++)
08776 cpl_polynomial_set_coeff(lin, &k,
08777 cpl_polynomial_get_coeff(ids, &k));
08778 }
08779 for (j = 0; j < countLines; j++) {
08780 pixe = cpl_bivector_get_x_data(output)[j];
08781 wave = cpl_bivector_get_y_data(output)[j];
08782 value = pixe
08783 - cpl_polynomial_eval_1d(ids, wave, NULL);
08784 if (residuals) {
08785 pixel = pixe + 0.5;
08786 (ddata + i*nx)[pixel] = value;
08787 }
08788 if (restable && !(i%step)) {
08789 for (k = 0; k < nref; k++) {
08790 if (fabs(line[k]-refwave-wave) < 0.1) {
08791 snprintf(name, MAX_COLNAME,
08792 "r%d", i);
08793 cpl_table_set_double(restable, name,
08794 k, value);
08795 value = pixe
08796 - cpl_polynomial_eval_1d(lin,
08797 wave, NULL);
08798 snprintf(name, MAX_COLNAME,
08799 "d%d", i);
08800 cpl_table_set_double(restable, name,
08801 k, value);
08802 snprintf(name, MAX_COLNAME,
08803 "p%d", i);
08804 cpl_table_set_double(restable, name,
08805 k, pixe);
08806 break;
08807 }
08808 }
08809 }
08810 }
08811 if (restable && !(i%step)) {
08812 cpl_polynomial_delete(lin);
08813 }
08814
08815
08816
08817
08818
08819
08820
08821
08822
08823
08824
08825 }
08826
08827 for (k = 0; k <= order; k++) {
08828 if (k > uorder) {
08829 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
08830 }
08831 else {
08832 cpl_table_set_double(idscoeff, clab[k], i,
08833 cpl_polynomial_get_coeff(ids, &k));
08834 }
08835 }
08836
08837 cpl_bivector_delete(output);
08838 cpl_polynomial_delete(ids);
08839
08840 }
08841
08842 cpl_polynomial_delete(fguess);
08843 }
08844
08845 cpl_table_delete(coeff);
08846
08847 }
08848
08849 row_top = row_bot;
08850
08851 }
08852
08853
08854
08855
08856
08857
08858
08859
08860
08861 for (i = 0; i < ny; i++) {
08862
08863 missing = 0;
08864 ids = cpl_polynomial_new(1);
08865 for (k = 0; k <= order; k++) {
08866 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
08867 if (null) {
08868 cpl_polynomial_delete(ids);
08869 missing = 1;
08870 break;
08871 }
08872 cpl_polynomial_set_coeff(ids, &k, c);
08873 }
08874 if (missing)
08875 continue;
08876
08877 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
08878 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
08879 if (pixstart < 0)
08880 pixstart = 0;
08881 if (pixend > nx)
08882 pixend = nx;
08883
08884
08885
08886
08887
08888 for (j = 0; j < nl; j++) {
08889 lambda = firstLambda + j * dispersion;
08890 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave, NULL);
08891 pixel = fpixel;
08892 if (pixel >= 0 && pixel < nx-1) {
08893 v1 = (sdata + i*nx)[pixel];
08894 v2 = (sdata + i*nx)[pixel+1];
08895 vi = v1 + (v2-v1)*(fpixel-pixel);
08896 (rdata + i*nl)[j] = vi;
08897 }
08898 }
08899
08900 cpl_polynomial_delete(ids);
08901 }
08902
08903 return resampled;
08904 }
08905
08906
08933 cpl_image *mos_wavelength_calibration(cpl_image *image, double refwave,
08934 double firstLambda, double lastLambda,
08935 double dispersion, cpl_table *idscoeff,
08936 int flux)
08937 {
08938
08939 const char *func = "mos_wavelength_calibration";
08940
08941 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
08942
08943
08944 cpl_image *resampled;
08945 cpl_polynomial *ids;
08946 double pixel_per_lambda;
08947 double lambda;
08948 double c;
08949 float *sdata;
08950 float *rdata;
08951 float v0, v1, v2, v3, vi;
08952 float fpixel;
08953 int order;
08954 int pixstart, pixend;
08955 int nl, nx, ny, pixel;
08956 int missing;
08957 int null;
08958 int i, j, k;
08959
08960
08961 if (dispersion <= 0.0) {
08962 cpl_msg_error(func, "The resampling step must be positive");
08963 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08964 return NULL;
08965 }
08966
08967 if (lastLambda - firstLambda < dispersion) {
08968 cpl_msg_error(func, "Invalid spectral range: %.2f to %.2f",
08969 firstLambda, lastLambda);
08970 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08971 return NULL;
08972 }
08973
08974 if (idscoeff == NULL) {
08975 cpl_msg_error(func, "An IDS coeff table must be given");
08976 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08977 return NULL;
08978 }
08979
08980 if (image == NULL) {
08981 cpl_msg_error(func, "A scientific spectral image must be given");
08982 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08983 return NULL;
08984 }
08985
08986 nx = cpl_image_get_size_x(image);
08987 ny = cpl_image_get_size_y(image);
08988 sdata = cpl_image_get_data_float(image);
08989
08990 nl = (lastLambda - firstLambda) / dispersion;
08991 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
08992 rdata = cpl_image_get_data_float(resampled);
08993
08994 order = 0;
08995 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
08996 ++order;
08997 --order;
08998
08999 for (i = 0; i < ny; i++) {
09000
09001 missing = 0;
09002 ids = cpl_polynomial_new(1);
09003 for (k = 0; k <= order; k++) {
09004 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
09005 if (null) {
09006 cpl_polynomial_delete(ids);
09007 missing = 1;
09008 break;
09009 }
09010 cpl_polynomial_set_coeff(ids, &k, c);
09011 }
09012 if (missing)
09013 continue;
09014
09015 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
09016 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
09017 if (pixstart < 0)
09018 pixstart = 0;
09019 if (pixend > nx)
09020 pixend = nx;
09021
09022
09023
09024
09025
09026 for (j = 0; j < nl; j++) {
09027 lambda = firstLambda + j * dispersion;
09028 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
09029 &pixel_per_lambda);
09030
09031
09032
09033
09034
09035
09036
09037 pixel = fpixel;
09038 if (pixel >= 1 && pixel < nx-2) {
09039 v0 = (sdata + i*nx)[pixel-1];
09040 v1 = (sdata + i*nx)[pixel];
09041 v2 = (sdata + i*nx)[pixel+1];
09042 v3 = (sdata + i*nx)[pixel+2];
09043 vi = (fpixel-pixel)*(fpixel-pixel)*(v3 - v2 - v1 + v0)
09044 + (fpixel-pixel)*(3*v2 - v3 - v1 - v0)
09045 + 2*v1;
09046 vi /= 2;
09047 if (v1 > v2) {
09048 if (vi > v1) {
09049 vi = v1;
09050 }
09051 else if (vi < v2) {
09052 vi = v2;
09053 }
09054 }
09055 else {
09056 if (vi > v2) {
09057 vi = v2;
09058 }
09059 else if (vi < v1) {
09060 vi = v1;
09061 }
09062 }
09063 if (flux)
09064 vi *= dispersion * pixel_per_lambda;
09065 (rdata + i*nl)[j] = vi;
09066 }
09067 else if (pixel >= 0 && pixel < nx-1) {
09068 v1 = (sdata + i*nx)[pixel];
09069 v2 = (sdata + i*nx)[pixel+1];
09070 vi = v1 + (v2-v1)*(fpixel-pixel);
09071 if (flux)
09072 vi *= dispersion * pixel_per_lambda;
09073 (rdata + i*nl)[j] = vi;
09074 }
09075 }
09076
09077 cpl_polynomial_delete(ids);
09078 }
09079
09080 return resampled;
09081 }
09082
09083
09150 cpl_table *mos_wavelength_align(cpl_image *image, cpl_table *slits,
09151 double refwave, double firstLambda,
09152 double lastLambda, cpl_table *idscoeff,
09153 cpl_vector *skylines, int highres, int order,
09154 cpl_image *calibration, int sradius)
09155 {
09156 const char *func = "mos_wavelength_align";
09157
09158 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
09159
09160 double *line;
09161 double *data;
09162 double expPos, offset;
09163 double c;
09164 double lambda1, lambda2;
09165 double rms;
09166 float pos;
09167 float *sdata;
09168 float *cdata;
09169 int *idata;
09170 int startPos, endPos;
09171 int window = 2*sradius + 1;
09172 int nlines;
09173 int nslits;
09174 int npoints;
09175 int nrows;
09176 int nx, ny;
09177 int xlow, ylow, xhig, yhig;
09178 int idsorder, uorder;
09179 int *slit_id;
09180 int *position;
09181 int *length;
09182 int missing;
09183 int null;
09184 int i, j, k;
09185
09186 char offname[MAX_COLNAME];
09187 char name[MAX_COLNAME];
09188
09189 cpl_polynomial *ids;
09190 cpl_polynomial *polycorr;
09191 cpl_image *exslit;
09192 cpl_image *sky;
09193 cpl_table *offsets;
09194 cpl_table *dummy;
09195 cpl_vector *wave;
09196 cpl_vector *offs;
09197
09198
09199 if (idscoeff == NULL) {
09200 cpl_msg_error(func, "An IDS coeff table must be given");
09201 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09202 return NULL;
09203 }
09204
09205 if (image == NULL) {
09206 cpl_msg_error(func, "A scientific spectral image must be given");
09207 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09208 return NULL;
09209 }
09210
09211 if (slits == NULL) {
09212 cpl_msg_error(func, "A slit position table must be given");
09213 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09214 return NULL;
09215 }
09216
09217 if (skylines) {
09218 line = cpl_vector_get_data(skylines);
09219 nlines = cpl_vector_get_size(skylines);
09220 }
09221 else {
09222 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
09223 "given: using internal list of reference sky lines");
09224 if (highres) {
09225 line = default_lines_hi;
09226 nlines = sizeof(default_lines_hi) / sizeof(double);
09227 }
09228 else {
09229 line = default_lines_lo;
09230 nlines = sizeof(default_lines_lo) / sizeof(double);
09231 }
09232 }
09233
09234 if (calibration)
09235 cdata = cpl_image_get_data(calibration);
09236
09237 nx = cpl_image_get_size_x(image);
09238 ny = cpl_image_get_size_y(image);
09239
09240 nslits = cpl_table_get_nrow(slits);
09241 slit_id = cpl_table_get_data_int(slits, "slit_id");
09242 position = cpl_table_get_data_int(slits, "position");
09243 length = cpl_table_get_data_int(slits, "length");
09244
09245
09246
09247
09248
09249
09250 nrows = 0;
09251 for (i = 0; i < nlines; i++)
09252 if (line[i] > firstLambda && line[i] < lastLambda)
09253 nrows++;
09254
09255 offsets = cpl_table_new(nrows);
09256 cpl_table_new_column(offsets, "wave", CPL_TYPE_DOUBLE);
09257 cpl_table_set_column_unit(offsets, "wave", "Angstrom");
09258
09259 nrows = 0;
09260 for (i = 0; i < nlines; i++) {
09261 if (line[i] > firstLambda && line[i] < lastLambda) {
09262 cpl_table_set_double(offsets, "wave", nrows, line[i]);
09263 nrows++;
09264 }
09265 }
09266
09267
09268
09269
09270
09271 line = cpl_table_get_data_double(offsets, "wave");
09272 nlines = nrows;
09273
09274 idsorder = 0;
09275 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
09276 ++idsorder;
09277 --idsorder;
09278
09279 xlow = 1;
09280 xhig = nx;
09281 for (i = 0; i < nslits; i++) {
09282
09283 if (length[i] == 0)
09284 continue;
09285
09286 snprintf(offname, MAX_COLNAME, "offset%d", slit_id[i]);
09287 cpl_table_new_column(offsets, offname, CPL_TYPE_DOUBLE);
09288
09289
09290
09291
09292
09293
09294
09295
09296
09297
09298
09299 ylow = position[i] + 1;
09300 yhig = ylow + length[i] - 1;
09301
09302 exslit = cpl_image_extract(image, xlow, ylow, xhig, yhig);
09303 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
09304 sdata = cpl_image_get_data(sky);
09305
09306 cpl_image_delete(exslit);
09307
09308
09309
09310
09311
09312
09313 ylow--;
09314
09315
09316
09317
09318
09319
09320
09321 dummy = cpl_table_new(yhig - ylow);
09322 for (j = 0; j < nlines; j++) {
09323 snprintf(name, MAX_COLNAME, "%d", j);
09324 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
09325 }
09326
09327 for (j = ylow; j < yhig; j++) {
09328
09329
09330
09331
09332
09333 missing = 0;
09334 ids = cpl_polynomial_new(1);
09335 for (k = 0; k <= idsorder; k++) {
09336 c = cpl_table_get_double(idscoeff, clab[k], j, &null);
09337 if (null) {
09338 cpl_polynomial_delete(ids);
09339 missing = 1;
09340 break;
09341 }
09342 cpl_polynomial_set_coeff(ids, &k, c);
09343 }
09344 if (missing)
09345 continue;
09346
09347 for (k = 0; k < nlines; k++) {
09348 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
09349 startPos = expPos - sradius;
09350 endPos = startPos + window;
09351 if (startPos < 0 || endPos >= nx)
09352 continue;
09353
09354 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
09355 pos += startPos;
09356 offset = pos - expPos;
09357 snprintf(name, MAX_COLNAME, "%d", k);
09358 cpl_table_set_double(dummy, name, j - ylow, offset);
09359 }
09360 }
09361
09362 cpl_polynomial_delete(ids);
09363 }
09364
09365 cpl_image_delete(sky);
09366
09367 for (j = 0; j < nlines; j++) {
09368 snprintf(name, MAX_COLNAME, "%d", j);
09369 if (cpl_table_has_valid(dummy, name)) {
09370 offset = cpl_table_get_column_median(dummy, name);
09371 cpl_table_set_double(offsets, offname, j, offset);
09372 }
09373 }
09374
09375 cpl_table_delete(dummy);
09376
09377 }
09378
09379
09380
09381
09382
09383
09384
09385
09386 for (i = 0; i < nslits; i++) {
09387
09388 if (length[i] == 0)
09389 continue;
09390
09391 snprintf(offname, MAX_COLNAME, "offset%d", slit_id[i]);
09392
09393
09394
09395
09396
09397
09398 dummy = cpl_table_new(nlines);
09399 cpl_table_duplicate_column(dummy, "wave", offsets, "wave");
09400 cpl_table_duplicate_column(dummy, "offset", offsets, offname);
09401
09402 npoints = nlines - cpl_table_count_invalid(dummy, "offset");
09403 if (npoints == 0) {
09404 cpl_msg_warning(func, "No sky lines alignment was possible "
09405 "for slit ID=%d: no sky line found", slit_id[i]);
09406 cpl_table_delete(dummy);
09407 continue;
09408 }
09409
09410 uorder = order;
09411 if (npoints <= uorder) {
09412 uorder = npoints - 1;
09413 if (uorder) {
09414 cpl_msg_warning(func, "Just %d sky lines detected for slit "
09415 "ID=%d, while a polynomial order %d was "
09416 "requested. Using polynomial order %d for "
09417 "this slit!", npoints, slit_id[i], order,
09418 uorder);
09419 }
09420 else {
09421 cpl_msg_warning(func, "Just %d sky lines detected for slit "
09422 "ID=%d, while a polynomial order %d was "
09423 "requested. Computing a median offset for "
09424 "this slit!", npoints, slit_id[i], order);
09425 }
09426 }
09427
09428 cpl_table_erase_invalid(dummy);
09429
09430 if (uorder > 1) {
09431
09432
09433
09434
09435
09436 wave = cpl_vector_wrap(npoints,
09437 cpl_table_get_data_double(dummy, "wave"));
09438 offs = cpl_vector_wrap(npoints,
09439 cpl_table_get_data_double(dummy, "offset"));
09440
09441
09442
09443
09444
09445 cpl_vector_subtract_scalar(wave, refwave);
09446
09447 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
09448
09449 rms = sqrt(rms * (uorder + 1) / npoints);
09450
09451 cpl_vector_unwrap(wave);
09452 cpl_vector_unwrap(offs);
09453 cpl_table_delete(dummy);
09454
09455
09456
09457
09458
09459
09460 ylow = position[i];
09461 yhig = ylow + length[i];
09462
09463 for (j = 0; j <= uorder; j++) {
09464 data = cpl_table_get_data_double(idscoeff, clab[j]);
09465 c = cpl_polynomial_get_coeff(polycorr, &j);
09466 for (k = ylow; k < yhig; k++)
09467 data[k] += c;
09468 }
09469
09470 data = cpl_table_get_data_double(idscoeff, "error");
09471 for (k = ylow; k < yhig; k++)
09472 data[k] = sqrt(data[k]*data[k] + rms*rms);
09473
09474 idata = cpl_table_get_data_int(idscoeff, "nlines");
09475 for (k = ylow; k < yhig; k++)
09476 idata[k] = npoints;
09477
09478
09479
09480
09481
09482
09483 if (calibration) {
09484 for (j = ylow; j < yhig; j++) {
09485 for (k = 1; k < nx; k++) {
09486 lambda1 = cdata[k - 1 + j*nx];
09487 lambda2 = cdata[k + j*nx];
09488 if (lambda1 < 1.0 || lambda2 < 1.0)
09489 continue;
09490 offset = cpl_polynomial_eval_1d(polycorr,
09491 lambda1-refwave, NULL);
09492 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
09493 }
09494 }
09495 }
09496
09497 cpl_polynomial_delete(polycorr);
09498 }
09499 else if (uorder == 1) {
09500
09501
09502
09503
09504
09505 double q, m;
09506 cpl_bivector *list;
09507
09508
09509 wave = cpl_vector_wrap(npoints,
09510 cpl_table_get_data_double(dummy, "wave"));
09511 offs = cpl_vector_wrap(npoints,
09512 cpl_table_get_data_double(dummy, "offset"));
09513
09514 list = cpl_bivector_wrap_vectors(wave, offs);
09515
09516
09517
09518
09519
09520 cpl_vector_subtract_scalar(wave, refwave);
09521
09522 robustLinearFit(list, &q, &m, &rms);
09523
09524 rms = sqrt(rms * (uorder + 1) / npoints);
09525
09526 cpl_bivector_unwrap_vectors(list);
09527 cpl_vector_unwrap(wave);
09528 cpl_vector_unwrap(offs);
09529 cpl_table_delete(dummy);
09530
09531
09532
09533
09534
09535
09536 ylow = position[i];
09537 yhig = ylow + length[i];
09538
09539 for (j = 0; j <= uorder; j++) {
09540 data = cpl_table_get_data_double(idscoeff, clab[j]);
09541 if (j)
09542 c = m;
09543 else
09544 c = q;
09545 for (k = ylow; k < yhig; k++)
09546 data[k] += c;
09547 }
09548
09549 data = cpl_table_get_data_double(idscoeff, "error");
09550 for (k = ylow; k < yhig; k++)
09551 data[k] = sqrt(data[k]*data[k] + rms*rms);
09552
09553 idata = cpl_table_get_data_int(idscoeff, "nlines");
09554 for (k = ylow; k < yhig; k++)
09555 idata[k] = npoints;
09556
09557
09558
09559
09560
09561
09562 if (calibration) {
09563 for (j = ylow; j < yhig; j++) {
09564 for (k = 1; k < nx; k++) {
09565 lambda1 = cdata[k - 1 + j*nx];
09566 lambda2 = cdata[k + j*nx];
09567 if (lambda1 < 1.0 || lambda2 < 1.0)
09568 continue;
09569 offset = q + m*(lambda1-refwave);
09570 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
09571 }
09572 }
09573 }
09574 }
09575 else {
09576
09577
09578
09579
09580
09581 offs = cpl_vector_wrap(npoints,
09582 cpl_table_get_data_double(dummy, "offset"));
09583
09584 offset = cpl_vector_get_median_const(offs);
09585
09586 if (npoints > 1)
09587 rms = cpl_table_get_column_stdev(dummy, "offset");
09588 else
09589 rms = 0.0;
09590
09591 rms /= sqrt(npoints);
09592
09593 cpl_vector_unwrap(offs);
09594 cpl_table_delete(dummy);
09595
09596
09597
09598
09599
09600
09601 ylow = position[i];
09602 yhig = ylow + length[i];
09603
09604 data = cpl_table_get_data_double(idscoeff, clab[0]);
09605 for (k = ylow; k < yhig; k++)
09606 data[k] += offset;
09607
09608 data = cpl_table_get_data_double(idscoeff, "error");
09609 for (k = ylow; k < yhig; k++)
09610 data[k] = sqrt(data[k]*data[k] + rms*rms);
09611
09612 idata = cpl_table_get_data_int(idscoeff, "nlines");
09613 for (k = ylow; k < yhig; k++)
09614 idata[k] = npoints;
09615
09616
09617
09618
09619
09620
09621
09622 if (calibration) {
09623 for (j = ylow; j < yhig; j++) {
09624 for (k = 1; k < nx; k++) {
09625 lambda1 = cdata[k - 1 + j*nx];
09626 lambda2 = cdata[k + j*nx];
09627 if (lambda1 < 1.0 || lambda2 < 1.0)
09628 continue;
09629 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
09630 }
09631 }
09632 }
09633 }
09634 }
09635
09636 return offsets;
09637
09638 }
09639
09640
09702 cpl_table *mos_wavelength_align_lss(cpl_image *image, double refwave,
09703 double firstLambda, double lastLambda,
09704 cpl_table *idscoeff, cpl_vector *skylines,
09705 int highres, int order,
09706 cpl_image *calibration, int sradius)
09707 {
09708 const char *func = "mos_wavelength_align_lss";
09709
09710 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
09711
09712 double *line;
09713 double *data;
09714 double *wdata;
09715 double *odata;
09716 double expPos, offset;
09717 double c;
09718 double lambda1, lambda2;
09719 double rms;
09720 float pos;
09721 float *sdata;
09722 float *cdata;
09723 int *idata;
09724 int startPos, endPos;
09725 int window = 2*sradius + 1;
09726 int nlines;
09727 int npoints;
09728 int nrows;
09729 int nx, ny;
09730 int idsorder, uorder;
09731 int missing;
09732 int i, j, k;
09733
09734 char name[MAX_COLNAME];
09735 char fname[MAX_COLNAME];
09736
09737 cpl_polynomial *ids;
09738 cpl_polynomial *polycorr;
09739 cpl_table *offsets;
09740 cpl_table *fittable;
09741 cpl_table *dummy;
09742 cpl_vector *wave;
09743 cpl_vector *offs;
09744 cpl_vector *row;
09745
09746
09747 if (idscoeff == NULL) {
09748 cpl_msg_error(func, "An IDS coeff table must be given");
09749 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09750 return NULL;
09751 }
09752
09753 if (image == NULL) {
09754 cpl_msg_error(func, "A scientific spectral image must be given");
09755 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09756 return NULL;
09757 }
09758
09759 if (skylines) {
09760 line = cpl_vector_get_data(skylines);
09761 nlines = cpl_vector_get_size(skylines);
09762 }
09763 else {
09764 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
09765 "given: using internal list of reference sky lines");
09766 if (highres) {
09767 line = default_lines_hi;
09768 nlines = sizeof(default_lines_hi) / sizeof(double);
09769 }
09770 else {
09771 line = default_lines_lo;
09772 nlines = sizeof(default_lines_lo) / sizeof(double);
09773 }
09774 }
09775
09776 if (calibration)
09777 cdata = cpl_image_get_data(calibration);
09778
09779 nx = cpl_image_get_size_x(image);
09780 ny = cpl_image_get_size_y(image);
09781
09782 sdata = cpl_image_get_data(image);
09783
09784
09785
09786
09787
09788
09789
09790
09791
09792
09793 nrows = 0;
09794 for (i = 0; i < nlines; i++)
09795 if (line[i] > firstLambda && line[i] < lastLambda)
09796 nrows++;
09797
09798 offsets = cpl_table_new(nrows);
09799 cpl_table_new_column(offsets, "wave", CPL_TYPE_DOUBLE);
09800 cpl_table_set_column_unit(offsets, "wave", "Angstrom");
09801
09802 nrows = 0;
09803 for (i = 0; i < nlines; i++) {
09804 if (line[i] > firstLambda && line[i] < lastLambda) {
09805 cpl_table_set_double(offsets, "wave", nrows, line[i]);
09806 nrows++;
09807 }
09808 }
09809
09810
09811
09812
09813
09814 line = cpl_table_get_data_double(offsets, "wave");
09815 nlines = nrows;
09816
09817 idsorder = 0;
09818 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
09819 ++idsorder;
09820 --idsorder;
09821
09822
09823
09824
09825
09826
09827
09828 dummy = cpl_table_new(ny);
09829 for (j = 0; j < nlines; j++) {
09830 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
09831 snprintf(fname, MAX_COLNAME, "fit_%d", (int)line[j]);
09832 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
09833 cpl_table_new_column(dummy, fname, CPL_TYPE_DOUBLE);
09834 }
09835
09836 for (j = 0; j < ny; j++, sdata += nx) {
09837
09838
09839
09840
09841
09842 missing = 0;
09843 ids = cpl_polynomial_new(1);
09844 for (k = 0; k <= idsorder; k++) {
09845 c = cpl_table_get_double(idscoeff, clab[k], j, &missing);
09846 if (missing) {
09847 cpl_polynomial_delete(ids);
09848 break;
09849 }
09850 cpl_polynomial_set_coeff(ids, &k, c);
09851 }
09852 if (missing)
09853 continue;
09854
09855 for (k = 0; k < nlines; k++) {
09856 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
09857 startPos = expPos - sradius;
09858 endPos = startPos + window;
09859 if (startPos < 0 || endPos >= nx)
09860 continue;
09861
09862 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
09863 pos += startPos;
09864 offset = pos - expPos;
09865 snprintf(name, MAX_COLNAME, "off_%d", (int)line[k]);
09866 cpl_table_set_double(dummy, name, j, offset);
09867 }
09868 }
09869
09870 cpl_polynomial_delete(ids);
09871 }
09872
09873
09874
09875
09876
09877
09878
09879 for (j = 0; j < nlines; j++) {
09880 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
09881 snprintf(fname, MAX_COLNAME, "fit_%d", (int)line[j]);
09882 if (cpl_table_has_valid(dummy, name)) {
09883
09884
09885
09886
09887
09888
09889 double q, m;
09890 cpl_bivector *list;
09891
09892 fittable = cpl_table_new(ny);
09893 cpl_table_new_column(fittable, "row", CPL_TYPE_DOUBLE);
09894 cpl_table_set_column_unit(fittable, "row", "pixel");
09895 for (k = 0; k < ny; k++)
09896 cpl_table_set_double(fittable, "row", k, k);
09897 cpl_table_duplicate_column(fittable, "offset", dummy, name);
09898 npoints = ny - cpl_table_count_invalid(fittable, "offset");
09899 cpl_table_erase_invalid(fittable);
09900 row = cpl_vector_wrap(npoints,
09901 cpl_table_get_data_double(fittable, "row"));
09902 offs = cpl_vector_wrap(npoints,
09903 cpl_table_get_data_double(fittable, "offset"));
09904 list = cpl_bivector_wrap_vectors(row, offs);
09905 robustLinearFit(list, &q, &m, &rms);
09906 cpl_bivector_unwrap_vectors(list);
09907 cpl_vector_unwrap(row);
09908 cpl_vector_unwrap(offs);
09909 cpl_table_delete(fittable);
09910 for (k = 0; k < ny; k++)
09911 cpl_table_set_double(dummy, fname, k, q + m*k);
09912 }
09913 }
09914
09915
09916
09917
09918
09919
09920
09921
09922
09923
09924 for (i = 0; i < ny; i++) {
09925
09926 if (!cpl_table_is_valid(idscoeff, clab[0], i))
09927 continue;
09928
09929 npoints = 0;
09930 for (j = 0; j < nlines; j++) {
09931 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
09932 if (cpl_table_is_valid(dummy, name, i))
09933 npoints++;
09934 }
09935
09936 if (npoints == 0)
09937 continue;
09938
09939 uorder = order;
09940 if (npoints <= uorder)
09941 uorder = npoints - 1;
09942
09943 if (uorder > 1) {
09944
09945
09946
09947
09948
09949 wave = cpl_vector_new(npoints);
09950 wdata = cpl_vector_get_data(wave);
09951 offs = cpl_vector_new(npoints);
09952 odata = cpl_vector_get_data(offs);
09953
09954 npoints = 0;
09955 for (j = 0; j < nlines; j++) {
09956 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
09957 if (cpl_table_is_valid(dummy, name, i)) {
09958 wdata[npoints] = line[j] - refwave;
09959 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
09960 npoints++;
09961 }
09962 }
09963
09964 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
09965
09966 rms = sqrt(rms * (uorder + 1) / npoints);
09967
09968 cpl_vector_delete(wave);
09969 cpl_vector_delete(offs);
09970
09971
09972
09973
09974
09975
09976 for (j = 0; j <= uorder; j++) {
09977 data = cpl_table_get_data_double(idscoeff, clab[j]);
09978 c = cpl_polynomial_get_coeff(polycorr, &j);
09979 data[i] += c;
09980 }
09981
09982 data = cpl_table_get_data_double(idscoeff, "error");
09983 data[i] = sqrt(data[i]*data[i] + rms*rms);
09984
09985 idata = cpl_table_get_data_int(idscoeff, "nlines");
09986 idata[i] = npoints;
09987
09988
09989
09990
09991
09992
09993 if (calibration) {
09994 for (k = 1; k < nx; k++) {
09995 lambda1 = cdata[k - 1 + i*nx];
09996 lambda2 = cdata[k + i*nx];
09997 if (lambda1 < 1.0 || lambda2 < 1.0)
09998 continue;
09999 offset = cpl_polynomial_eval_1d(polycorr,
10000 lambda1-refwave, NULL);
10001 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10002 }
10003 }
10004
10005 cpl_polynomial_delete(polycorr);
10006
10007 }
10008 else if (uorder == 1) {
10009
10010
10011
10012
10013
10014 cpl_bivector *list;
10015 double q, m;
10016
10017 wave = cpl_vector_new(npoints);
10018 wdata = cpl_vector_get_data(wave);
10019 offs = cpl_vector_new(npoints);
10020 odata = cpl_vector_get_data(offs);
10021
10022 npoints = 0;
10023 for (j = 0; j < nlines; j++) {
10024 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
10025 if (cpl_table_is_valid(dummy, name, i)) {
10026 wdata[npoints] = line[j] - refwave;
10027 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10028 npoints++;
10029 }
10030 }
10031
10032 list = cpl_bivector_wrap_vectors(wave, offs);
10033 robustLinearFit(list, &q, &m, &rms);
10034
10035 rms = sqrt(rms * (uorder + 1) / npoints);
10036
10037 cpl_bivector_unwrap_vectors(list);
10038 cpl_vector_delete(wave);
10039 cpl_vector_delete(offs);
10040
10041
10042
10043
10044
10045
10046 for (j = 0; j <= uorder; j++) {
10047 data = cpl_table_get_data_double(idscoeff, clab[j]);
10048 if (j)
10049 c = m;
10050 else
10051 c = q;
10052 data[i] += c;
10053 }
10054
10055 data = cpl_table_get_data_double(idscoeff, "error");
10056 data[i] = sqrt(data[i]*data[i] + rms*rms);
10057
10058 idata = cpl_table_get_data_int(idscoeff, "nlines");
10059 idata[i] = npoints;
10060
10061
10062
10063
10064
10065
10066 if (calibration) {
10067 for (k = 1; k < nx; k++) {
10068 lambda1 = cdata[k - 1 + i*nx];
10069 lambda2 = cdata[k + i*nx];
10070 if (lambda1 < 1.0 || lambda2 < 1.0)
10071 continue;
10072 offset = q + m*(lambda1-refwave);
10073 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10074 }
10075 }
10076 }
10077 else {
10078
10079
10080
10081
10082
10083 offs = cpl_vector_new(npoints);
10084 odata = cpl_vector_get_data(offs);
10085
10086 npoints = 0;
10087 for (j = 0; j < nlines; j++) {
10088 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
10089 if (cpl_table_is_valid(dummy, name, i)) {
10090 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10091 npoints++;
10092 }
10093 }
10094
10095 offset = cpl_vector_get_median_const(offs);
10096
10097 if (npoints > 1) {
10098 rms = cpl_vector_get_stdev(offs);
10099 }
10100 else if (npoints == 1) {
10101 snprintf(name, MAX_COLNAME, "off_%d", (int)line[0]);
10102 if (cpl_table_has_valid(dummy, name)) {
10103 rms = cpl_table_get_column_stdev(dummy, name);
10104 rms /= sqrt(ny - cpl_table_count_invalid(dummy, name));
10105 }
10106 else {
10107 rms = 0.0;
10108 }
10109 }
10110 else {
10111 rms = 0.0;
10112 }
10113
10114 rms /= sqrt(npoints);
10115
10116 cpl_vector_delete(offs);
10117
10118
10119
10120
10121
10122
10123 data = cpl_table_get_data_double(idscoeff, clab[0]);
10124 data[i] += offset;
10125
10126 data = cpl_table_get_data_double(idscoeff, "error");
10127 data[i] = sqrt(data[i]*data[i] + rms*rms);
10128
10129 idata = cpl_table_get_data_int(idscoeff, "nlines");
10130 idata[i] = npoints;
10131
10132
10133
10134
10135
10136
10137
10138 if (calibration) {
10139 for (k = 1; k < nx; k++) {
10140 lambda1 = cdata[k - 1 + i*nx];
10141 lambda2 = cdata[k + i*nx];
10142 if (lambda1 < 1.0 || lambda2 < 1.0)
10143 continue;
10144 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10145 }
10146 }
10147 }
10148 }
10149
10150 missing = 1;
10151 for (j = 0; j < nlines; j++) {
10152 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
10153 if (cpl_table_has_valid(dummy, name)) {
10154 missing = 0;
10155 offset = cpl_table_get_column_median(dummy, name);
10156 cpl_msg_info(func, "Median offset for %.3f: %.3f pixel",
10157 line[j], offset);
10158 }
10159 else {
10160 cpl_msg_info(func,
10161 "Median offset for %.2f: not available", line[j]);
10162 }
10163 }
10164
10165 cpl_table_delete(offsets);
10166
10167 if (missing) {
10168 cpl_table_delete(dummy);
10169 dummy = NULL;
10170 }
10171
10172 return dummy;
10173
10174 }
10175
10176
10204 double mos_distortions_rms(cpl_image *rectified, cpl_vector *lines,
10205 double wavestart, double dispersion, int radius,
10206 int highres)
10207 {
10208
10209 const char *func = "mos_distortions_rms";
10210
10211 int xlen;
10212 int ylen;
10213 int numLines;
10214 int cpix, npix, nzero;
10215 int sp, ep;
10216 int i, j, k;
10217 int npeaks, allPeaks;
10218
10219 float *profile;
10220 float peak, expectPeak, offset;
10221 double lambda;
10222
10223 double average;
10224 double rms, oneRms;
10225
10226 float *sdata;
10227 double *wdata;
10228
10229
10230 xlen = cpl_image_get_size_x(rectified);
10231 ylen = cpl_image_get_size_y(rectified);
10232 sdata = cpl_image_get_data(rectified);
10233
10234 if (lines) {
10235 wdata = cpl_vector_get_data(lines);
10236 numLines = cpl_vector_get_size(lines);
10237 }
10238 else {
10239 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
10240 "given: using internal list of reference sky lines");
10241 if (highres) {
10242 wdata = default_lines_hi;
10243 numLines = sizeof(default_lines_hi) / sizeof(double);
10244 }
10245 else {
10246 wdata = default_lines_lo;
10247 numLines = sizeof(default_lines_lo) / sizeof(double);
10248 }
10249 }
10250
10251 npix = 2 * radius + 1;
10252 profile = cpl_calloc(npix, sizeof(float));
10253
10254 rms = 0.0;
10255 allPeaks = 0;
10256
10257 for (i = 0; i < numLines; i++) {
10258
10259
10260
10261
10262
10263 lambda = wdata[i];
10264 expectPeak = (lambda - wavestart) / dispersion;
10265 cpix = floor(expectPeak + 0.5);
10266
10267
10268
10269
10270
10271 sp = cpix - radius;
10272 ep = cpix + radius;
10273
10274 if (sp < 0 || ep > xlen)
10275 continue;
10276
10277 average = 0.0;
10278 npeaks = 0;
10279 oneRms = 0.0;
10280
10281 for (j = 0; j < ylen; j++) {
10282 nzero = 0;
10283 for (k = 0; k < npix; k++) {
10284 profile[k] = sdata[sp + k + j * xlen];
10285 if (fabs(profile[k]) < 0.0001)
10286 nzero++;
10287 }
10288 if (nzero > 0)
10289 continue;
10290
10291 if (peakPosition(profile, npix, &peak, 1) == 0) {
10292 offset = (sp + peak) - expectPeak;
10293 average += offset;
10294 rms += fabs(offset);
10295 oneRms += fabs(offset);
10296 npeaks++;
10297 allPeaks++;
10298 }
10299 }
10300
10301 if (npeaks)
10302 cpl_msg_info(func, "RMS for %.2f: %.3f pixel (%d points)",
10303 lambda, oneRms / npeaks * 1.25, npeaks);
10304 else
10305 cpl_msg_info(func, "RMS for %.2f: line not available", lambda);
10306 }
10307
10308 cpl_free(profile);
10309
10310 if (allPeaks < 10)
10311 return 0.0;
10312
10313 rms /= allPeaks;
10314 rms *= 1.25;
10315
10316 return rms;
10317
10318 }
10319
10320
10341 cpl_image *mos_map_pixel(cpl_table *idscoeff, double reference,
10342 double blue, double red, double dispersion, int trend)
10343 {
10344 const char *func = "mos_map_pixel";
10345
10346 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10347
10348
10349 cpl_polynomial *ids;
10350 cpl_image *map;
10351 float *mdata;
10352 double lambda;
10353 double c;
10354 int order;
10355 int xsize, ysize;
10356 int missing;
10357 int i, j, k;
10358
10359
10360 if (idscoeff == NULL) {
10361 cpl_msg_error(func, "An IDS coeff table must be given");
10362 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10363 return NULL;
10364 }
10365
10366 xsize = (red - blue) / dispersion;
10367 ysize = cpl_table_get_nrow(idscoeff);
10368 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
10369 mdata = cpl_image_get_data(map);
10370
10371 order = 0;
10372 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
10373 ++order;
10374 --order;
10375
10376 for (i = 0; i < ysize; i++, mdata += xsize) {
10377
10378 missing = 0;
10379 ids = cpl_polynomial_new(1);
10380 for (k = trend; k <= order; k++) {
10381 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
10382 if (missing) {
10383 cpl_polynomial_delete(ids);
10384 break;
10385 }
10386 cpl_polynomial_set_coeff(ids, &k, c);
10387 }
10388 if (missing)
10389 continue;
10390
10391 for (j = 0; j < xsize; j++) {
10392 lambda = blue + j*dispersion;
10393 mdata[j] = cpl_polynomial_eval_1d(ids, lambda-reference, NULL);
10394 }
10395
10396 cpl_polynomial_delete(ids);
10397 }
10398
10399 return map;
10400
10401 }
10402
10403
10425 cpl_image *mos_map_idscoeff(cpl_table *idscoeff, int xsize, double reference,
10426 double blue, double red)
10427 {
10428 const char *func = "mos_map_idscoeff";
10429
10430 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10431
10432
10433 cpl_polynomial *ids;
10434 cpl_image *map;
10435 float *mdata;
10436 double lambda;
10437 double c;
10438 int order;
10439 int ysize;
10440 int missing;
10441 int i, j, k;
10442
10443
10444 if (idscoeff == NULL) {
10445 cpl_msg_error(func, "An IDS coeff table must be given");
10446 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10447 return NULL;
10448 }
10449
10450 if (xsize < 1) {
10451 cpl_msg_error(func, "Invalid image size");
10452 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10453 return NULL;
10454 }
10455
10456 if (xsize < 20 || xsize > 5000) {
10457 cpl_msg_warning(func, "Do you really have a detector %d pixels long?",
10458 xsize);
10459 }
10460
10461 ysize = cpl_table_get_nrow(idscoeff);
10462 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
10463 mdata = cpl_image_get_data(map);
10464
10465 order = 0;
10466 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
10467 ++order;
10468 --order;
10469
10470 for (i = 0; i < ysize; i++, mdata += xsize) {
10471
10472 missing = 0;
10473 ids = cpl_polynomial_new(1);
10474 for (k = 0; k <= order; k++) {
10475 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
10476 if (missing) {
10477 cpl_polynomial_delete(ids);
10478 break;
10479 }
10480 cpl_polynomial_set_coeff(ids, &k, c);
10481 }
10482 if (missing)
10483 continue;
10484
10485 for (j = 0; j < xsize; j++) {
10486 lambda = mos_eval_dds(ids, blue, red, reference, j);
10487 if (lambda >= blue && lambda <= red) {
10488 mdata[j] = lambda;
10489 }
10490 }
10491
10492 cpl_polynomial_delete(ids);
10493 }
10494
10495 return map;
10496
10497 }
10498
10499
10534 cpl_image *mos_map_wavelengths(cpl_image *spatial, cpl_image *calibration,
10535 cpl_table *slits, cpl_table *polytraces,
10536 double reference, double blue, double red,
10537 double dispersion)
10538 {
10539 const char *func = "mos_map_wavelengths";
10540
10541 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10542
10543 cpl_polynomial *polytop;
10544 cpl_polynomial *polybot;
10545 cpl_image *remapped;
10546 float *data;
10547 float *wdata;
10548 float *sdata;
10549 float *xdata;
10550 double vtop, vbot, value;
10551 double top, bot;
10552 double coeff;
10553 double ytop, ybot;
10554 double ypos;
10555 double fvalue;
10556 int ivalue;
10557 int yint, ysize, yprev;
10558 int nslits;
10559 int npseudo;
10560 int *slit_id;
10561 int *position;
10562 int *length;
10563 int nx, ny;
10564 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
10565 int missing_top, missing_bot;
10566 int null;
10567 int order;
10568 int i, j, k;
10569
10570
10571 if (spatial == NULL || calibration == NULL ||
10572 slits == NULL || polytraces == NULL) {
10573 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10574 return NULL;
10575 }
10576
10577 if (dispersion <= 0.0) {
10578 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10579 return NULL;
10580 }
10581
10582 if (red - blue < dispersion) {
10583 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10584 return NULL;
10585 }
10586
10587 nx = cpl_image_get_size_x(spatial);
10588 ny = cpl_image_get_size_y(spatial);
10589 ysize = cpl_image_get_size_y(calibration);
10590 remapped = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
10591 data = cpl_image_get_data(remapped);
10592 sdata = cpl_image_get_data(spatial);
10593 wdata = cpl_image_get_data(calibration);
10594
10595 nslits = cpl_table_get_nrow(slits);
10596 slit_id = cpl_table_get_data_int(slits, "slit_id");
10597 order = cpl_table_get_ncol(polytraces) - 2;
10598 position = cpl_table_get_data_int(slits, "position");
10599 length = cpl_table_get_data_int(slits, "length");
10600
10601
10602
10603
10604
10605
10606 pixel_above = (red - reference) / dispersion;
10607 pixel_below = (reference - blue) / dispersion;
10608
10609 for (i = 0; i < nslits; i++) {
10610
10611 if (length[i] == 0)
10612 continue;
10613
10614
10615
10616
10617
10618
10619
10620
10621
10622
10623
10624
10625 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
10626
10627 start_pixel = refpixel - pixel_below;
10628 if (start_pixel < 0)
10629 start_pixel = 0;
10630
10631 end_pixel = refpixel + pixel_above;
10632 if (end_pixel > nx)
10633 end_pixel = nx;
10634
10635
10636
10637
10638
10639
10640 missing_top = 0;
10641 polytop = cpl_polynomial_new(1);
10642 for (k = 0; k <= order; k++) {
10643 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
10644 if (null) {
10645 cpl_polynomial_delete(polytop);
10646 missing_top = 1;
10647 break;
10648 }
10649 cpl_polynomial_set_coeff(polytop, &k, coeff);
10650 }
10651
10652 missing_bot = 0;
10653 polybot = cpl_polynomial_new(1);
10654 for (k = 0; k <= order; k++) {
10655 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
10656 if (null) {
10657 cpl_polynomial_delete(polybot);
10658 missing_bot = 1;
10659 break;
10660 }
10661 cpl_polynomial_set_coeff(polybot, &k, coeff);
10662 }
10663
10664 if (missing_top && missing_bot) {
10665 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
10666 slit_id[i]);
10667 continue;
10668 }
10669
10670
10671
10672
10673
10674
10675
10676 if (missing_top) {
10677 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
10678 "the spectral curvature of the lower edge "
10679 "is used instead.", slit_id[i]);
10680 polytop = cpl_polynomial_duplicate(polybot);
10681 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
10682 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
10683 k = 0;
10684 coeff = cpl_polynomial_get_coeff(polybot, &k);
10685 coeff += ytop - ybot;
10686 cpl_polynomial_set_coeff(polytop, &k, coeff);
10687 }
10688
10689 if (missing_bot) {
10690 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
10691 "the spectral curvature of the upper edge "
10692 "is used instead.", slit_id[i]);
10693 polybot = cpl_polynomial_duplicate(polytop);
10694 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
10695 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
10696 k = 0;
10697 coeff = cpl_polynomial_get_coeff(polytop, &k);
10698 coeff -= ytop - ybot;
10699 cpl_polynomial_set_coeff(polybot, &k, coeff);
10700 }
10701
10702
10703
10704
10705
10706
10707
10708
10709 xdata = wdata + nx*position[i];
10710 npseudo = length[i] - 1;
10711
10712
10713
10714
10715
10716 for (j = start_pixel; j < end_pixel; j++) {
10717 top = cpl_polynomial_eval_1d(polytop, j, NULL);
10718 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
10719 for (k = 0; k <= npseudo; k++) {
10720 ypos = top - k*(top-bot)/npseudo;
10721 yint = ypos;
10722
10723
10724
10725
10726
10727
10728
10729
10730 if (yint < 0 || yint >= ny-1) {
10731 yprev = yint;
10732 continue;
10733 }
10734
10735 value = sdata[j + nx*yint];
10736 ivalue = value;
10737 fvalue = value - ivalue;
10738 if (ivalue < npseudo && ivalue >= 0) {
10739 vtop = xdata[j + nx*(npseudo-ivalue)];
10740 vbot = xdata[j + nx*(npseudo-ivalue-1)];
10741 if (vtop < 1.0) {
10742 if (vbot < 1.0) {
10743 value = 0.0;
10744 }
10745 else {
10746 value = vbot;
10747 }
10748 }
10749 else if (vbot < 1.0) {
10750 if (k)
10751 value = vtop;
10752 else
10753 value = 0.0;
10754 }
10755 else if (fabs(vbot-vtop) > 10*dispersion) {
10756 value = 0.0;
10757 }
10758 else {
10759 value = vtop*(1-fvalue) + vbot*fvalue;
10760 }
10761 data[j + nx*yint] = value;
10762
10763 if (k) {
10764
10765
10766
10767
10768
10769
10770
10771 if (yprev - yint > 1) {
10772 value = sdata[j + nx*(yint+1)];
10773 ivalue = value;
10774 fvalue = value - ivalue;
10775 if (ivalue < npseudo && ivalue >= 0) {
10776 vtop = xdata[j + nx*(npseudo-ivalue)];
10777 vbot = xdata[j + nx*(npseudo-ivalue-1)];
10778 if (vtop < 1.0) {
10779 if (vbot < 1.0) {
10780 value = data[j + nx*(yint+1)];
10781 }
10782 else {
10783 value = vbot;
10784 }
10785 }
10786 else if (vbot < 1.0) {
10787 value = vtop;
10788 }
10789 else if (fabs(vbot-vtop) > 2*dispersion) {
10790 value = vtop;
10791 }
10792 else {
10793 value = vtop*(1-fvalue) + vbot*fvalue;
10794 }
10795 data[j + nx*(yint+1)] = value;
10796 }
10797 }
10798 }
10799 }
10800 yprev = yint;
10801 }
10802 }
10803 cpl_polynomial_delete(polytop);
10804 cpl_polynomial_delete(polybot);
10805 }
10806
10807 return remapped;
10808 }
10809
10883 cpl_image *mos_map_spectrum(cpl_image *spectra, cpl_image *wavecalib,
10884 cpl_image *spatial, cpl_table *slits,
10885 cpl_table *polytraces, double reference,
10886 double blue, double red, double dispersion,
10887 int flux)
10888 {
10889 const char *func = "mos_map_spectrum";
10890
10891 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10892
10893 cpl_polynomial *polytop;
10894 cpl_polynomial *polybot;
10895 cpl_image *remapped;
10896 cpl_image **exslit;
10897 float *data;
10898 float *wdata;
10899 float *sdata;
10900 float *xdata;
10901 double lambda00, lambda01, lambda10, lambda11, lambda;
10902 double space00, space01, space10, space11, space;
10903 double value00, value01, value10, value11, value0, value1, value;
10904 double dL, dS;
10905 double top, bot;
10906 double coeff;
10907 double ytop, ybot;
10908 double xfrac, yfrac;
10909 int yint, ysize;
10910 int itop, ibot;
10911 int shift;
10912 int L, S;
10913 int nslits;
10914 int npseudo;
10915 int *slit_id;
10916 int *position;
10917 int *length;
10918 int nx, ny;
10919 int x, y;
10920 int nlambda;
10921 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
10922 int missing_top, missing_bot;
10923 int null;
10924 int order;
10925 int i, k;
10926
10927
10928 flux += flux;
10929
10930 if (spectra == NULL || spatial == NULL || wavecalib == NULL ||
10931 slits == NULL || polytraces == NULL) {
10932 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10933 return NULL;
10934 }
10935
10936 if (dispersion <= 0.0) {
10937 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10938 return NULL;
10939 }
10940
10941 if (red - blue < dispersion) {
10942 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10943 return NULL;
10944 }
10945
10946 nx = cpl_image_get_size_x(spectra);
10947 ny = cpl_image_get_size_y(spectra);
10948
10949 if (nx != cpl_image_get_size_x(spatial) ||
10950 ny != cpl_image_get_size_y(spatial) ||
10951 nx != cpl_image_get_size_x(wavecalib) ||
10952 ny != cpl_image_get_size_y(wavecalib)) {
10953 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
10954 return NULL;
10955 }
10956
10957 nlambda = (red - blue) / dispersion;
10958 pixel_above = (red - reference) / dispersion;
10959 pixel_below = (reference - blue) / dispersion;
10960
10961 data = cpl_image_get_data(spectra);
10962 sdata = cpl_image_get_data(spatial);
10963 wdata = cpl_image_get_data(wavecalib);
10964
10965 nslits = cpl_table_get_nrow(slits);
10966 slit_id = cpl_table_get_data_int(slits, "slit_id");
10967 order = cpl_table_get_ncol(polytraces) - 2;
10968 position = cpl_table_get_data_int(slits, "position");
10969 length = cpl_table_get_data_int(slits, "length");
10970
10971 exslit = cpl_calloc(nslits, sizeof(cpl_image *));
10972
10973 for (i = 0; i < nslits; i++) {
10974
10975 if (length == 0)
10976 continue;
10977
10978
10979
10980
10981
10982
10983
10984
10985
10986
10987
10988
10989 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
10990
10991 start_pixel = refpixel - pixel_below;
10992 if (start_pixel < 1)
10993 start_pixel = 1;
10994
10995 end_pixel = refpixel + pixel_above;
10996 if (end_pixel > nx)
10997 end_pixel = nx;
10998
10999
11000
11001
11002
11003
11004 missing_top = 0;
11005 polytop = cpl_polynomial_new(1);
11006 for (k = 0; k <= order; k++) {
11007 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
11008 if (null) {
11009 cpl_polynomial_delete(polytop);
11010 missing_top = 1;
11011 break;
11012 }
11013 cpl_polynomial_set_coeff(polytop, &k, coeff);
11014 }
11015
11016 missing_bot = 0;
11017 polybot = cpl_polynomial_new(1);
11018 for (k = 0; k <= order; k++) {
11019 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
11020 if (null) {
11021 cpl_polynomial_delete(polybot);
11022 missing_bot = 1;
11023 break;
11024 }
11025 cpl_polynomial_set_coeff(polybot, &k, coeff);
11026 }
11027
11028 if (missing_top && missing_bot) {
11029 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
11030 slit_id[i]);
11031 continue;
11032 }
11033
11034
11035
11036
11037
11038
11039
11040 if (missing_top) {
11041 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
11042 "the spectral curvature of the lower edge "
11043 "is used instead.", slit_id[i]);
11044 polytop = cpl_polynomial_duplicate(polybot);
11045 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
11046 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
11047 k = 0;
11048 coeff = cpl_polynomial_get_coeff(polybot, &k);
11049 coeff += ytop - ybot;
11050 cpl_polynomial_set_coeff(polytop, &k, coeff);
11051 }
11052
11053 if (missing_bot) {
11054 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
11055 "the spectral curvature of the upper edge "
11056 "is used instead.", slit_id[i]);
11057 polybot = cpl_polynomial_duplicate(polytop);
11058 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
11059 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
11060 k = 0;
11061 coeff = cpl_polynomial_get_coeff(polytop, &k);
11062 coeff -= ytop - ybot;
11063 cpl_polynomial_set_coeff(polybot, &k, coeff);
11064 }
11065
11066
11067
11068
11069
11070 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
11071 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
11072 npseudo = ceil(top-bot) + 1;
11073
11074 if (npseudo < 1) {
11075 cpl_polynomial_delete(polytop);
11076 cpl_polynomial_delete(polybot);
11077 cpl_msg_debug(func, "Slit %d was badly traced: no extraction!",
11078 slit_id[i]);
11079 continue;
11080 }
11081
11082 exslit[i] = cpl_image_new(nlambda, npseudo+1, CPL_TYPE_FLOAT);
11083 xdata = cpl_image_get_data(exslit[i]);
11084
11085
11086
11087
11088
11089 for (x = start_pixel; x < end_pixel; x++) {
11090 top = cpl_polynomial_eval_1d(polytop, x, NULL);
11091 bot = cpl_polynomial_eval_1d(polybot, x, NULL);
11092 itop = top + 1;
11093 ibot = bot;
11094 if (itop < 0)
11095 itop = 0;
11096 if (itop > ny - 1)
11097 itop = ny - 1;
11098 if (ibot < 0)
11099 ibot = 0;
11100 if (ibot > ny - 1)
11101 ibot = ny - 1;
11102 for (y = ibot; y < itop; y++) {
11103 lambda11 = wdata[x + y*nx];
11104 if (lambda11 < 1.0)
11105 continue;
11106 space11 = sdata[x + y*nx];
11107 if (space11 < 0.0)
11108 continue;
11109 lambda01 = wdata[x - 1 + y*nx];
11110 if (lambda01 < 1.0)
11111 continue;
11112 space01 = sdata[x - 1 + y*nx];
11113 if (space01 < 0.0)
11114 continue;
11115
11116 shift = 0;
11117
11118
11119
11120
11121
11122
11123
11124
11125
11126
11127
11128
11129
11130
11131
11132
11133
11134
11135
11136
11137
11138
11139
11140
11141
11142
11143
11144
11145 lambda10 = wdata[x + shift + (y+1)*nx];
11146 if (lambda10 < 1.0)
11147 continue;
11148 space10 = sdata[x + shift + (y+1)*nx];
11149 if (space10 < 0.0)
11150 continue;
11151 lambda00 = wdata[x - 1 + shift + (y+1)*nx];
11152 if (lambda00 < 1.0)
11153 continue;
11154 space00 = sdata[x - 1 + shift + (y+1)*nx];
11155 if (space00 < 0.0)
11156 continue;
11157
11158
11159
11160
11161
11162
11163
11164 dL = lambda11 - lambda01;
11165 dS = space11 - space10;
11166
11167
11168
11169
11170
11171
11172 L = (lambda11 - blue)/dispersion + 0.5;
11173 S = space11 + 0.5;
11174
11175 if (L < 0 || L >= nlambda)
11176 continue;
11177 if (S < 0 || S > npseudo)
11178 continue;
11179
11180
11181
11182
11183
11184 lambda = blue + L*dispersion;
11185 space = S;
11186
11187
11188
11189
11190
11191
11192
11193
11194
11195
11196 xfrac = (lambda11-lambda)/dL;
11197 yfrac = (space11-space)/dS;
11198
11199
11200
11201
11202
11203
11204
11205
11206
11207
11208 value11 = data[x + y*nx];
11209 value01 = data[x - 1 + y*nx];
11210 value10 = data[x + shift + (y+1)*nx];
11211 value00 = data[x + shift - 1 + (y+1)*nx];
11212
11213
11214
11215
11216
11217 value1 = (1-xfrac)*value11 + xfrac*value01;
11218 value0 = (1-xfrac)*value10 + xfrac*value00;
11219 value = (1-yfrac)*value1 + yfrac*value0;
11220
11221
11222
11223
11224
11225
11226 xdata[L + nlambda*(npseudo-S)] = value;
11227
11228 }
11229 }
11230 cpl_polynomial_delete(polytop);
11231 cpl_polynomial_delete(polybot);
11232 }
11233
11234
11235
11236
11237
11238 ysize = 0;
11239 for (i = 0; i < nslits; i++)
11240 if (exslit[i])
11241 ysize += cpl_image_get_size_y(exslit[i]);
11242
11243 remapped = cpl_image_new(nlambda, ysize, CPL_TYPE_FLOAT);
11244
11245 yint = -1;
11246 for (i = 0; i < nslits; i++) {
11247 if (exslit[i]) {
11248 yint += cpl_image_get_size_y(exslit[i]);
11249 cpl_image_copy(remapped, exslit[i], 1, ysize - yint);
11250 cpl_image_delete(exslit[i]);
11251 cpl_table_set_int(slits, "position", i, ysize - yint - 1);
11252 }
11253 }
11254
11255 cpl_free(exslit);
11256
11257 return remapped;
11258
11259 }
11260
11261
11294 cpl_table *mos_sky_map_super(cpl_image *spectra, cpl_image *wavemap,
11295 double dispersion, double factor, int minpoints,
11296 cpl_image *skymap)
11297 {
11298 const char *func = "mos_sky_map_super";
11299
11300 cpl_vector **vector;
11301 cpl_vector **wvector;
11302 double firstLambda, lastLambda;
11303 double lambda, lambda1, lambda2;
11304 double value, value1, value2;
11305 double frac;
11306 float min, max;
11307 int *count;
11308 int nbin, bin;
11309 int nx, ny, npix;
11310 int first_valid, valid_bins;
11311 int i, j;
11312
11313 cpl_table *sky;
11314 double *sky_spectrum;
11315 double *sky_wave;
11316 float *data;
11317 float *sdata;
11318 float *kdata;
11319
11320
11321 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
11322 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11323 return NULL;
11324 }
11325
11326 if (dispersion <= 0.0) {
11327 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11328 cpl_msg_error(func, "Negative dispersion: %s", cpl_error_get_message());
11329 return NULL;
11330 }
11331
11332 nx = cpl_image_get_size_x(spectra);
11333 ny = cpl_image_get_size_y(spectra);
11334 npix = nx * ny;
11335
11336 if (nx != cpl_image_get_size_x(wavemap) ||
11337 ny != cpl_image_get_size_y(wavemap) ||
11338 nx != cpl_image_get_size_x(skymap) ||
11339 ny != cpl_image_get_size_y(skymap)) {
11340 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
11341 cpl_msg_error(func, "Image sizes: %s", cpl_error_get_message());
11342 return NULL;
11343 }
11344
11345 if (factor < 1.0) {
11346 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11347 cpl_msg_error(func, "Undersampling (%f): %s", factor,
11348 cpl_error_get_message());
11349 return NULL;
11350 }
11351
11352 if (minpoints < 0) {
11353 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11354 cpl_msg_error(func, "Negative threshold: %s", cpl_error_get_message());
11355 return NULL;
11356 }
11357
11358 dispersion /= factor;
11359
11360
11361
11362
11363
11364
11365 data = cpl_image_get_data(wavemap);
11366
11367 for (i = 0; i < npix; i++) {
11368 if (data[i] > 1.0) {
11369 min = max = data[i];
11370 j = i+1;
11371 break;
11372 }
11373 }
11374
11375 for (i = j; i < npix; i++) {
11376 if (data[i] < 1.0)
11377 continue;
11378 if (min > data[i])
11379 min = data[i];
11380 if (max < data[i])
11381 max = data[i];
11382 }
11383
11384 firstLambda = min;
11385 lastLambda = max;
11386
11387
11388
11389
11390
11391
11392 nbin = (lastLambda - firstLambda) / dispersion;
11393
11394
11395
11396
11397
11398
11399
11400
11401 count = cpl_calloc(nbin, sizeof(int));
11402
11403 data = cpl_image_get_data(wavemap);
11404
11405 for (i = 0; i < npix; i++) {
11406 if (data[i] < 1.0)
11407 continue;
11408 bin = (data[i] - firstLambda) / dispersion;
11409 if (bin < nbin)
11410 count[bin]++;
11411 }
11412
11413 valid_bins = 0;
11414 for (i = 0; i < nbin; i++)
11415 if (count[i] >= minpoints)
11416 valid_bins++;
11417
11418 if (valid_bins < nbin/3) {
11419 cpl_msg_warning(func, "Cannot determine a good global sky "
11420 "spectrum from input data");
11421 return NULL;
11422 }
11423
11424
11425
11426
11427
11428
11429
11430
11431
11432 vector = cpl_calloc(nbin, sizeof(cpl_vector *));
11433 wvector = cpl_calloc(nbin, sizeof(cpl_vector *));
11434 for (i = 0; i < nbin; i++) {
11435 if (count[i] >= minpoints) {
11436 vector[i] = cpl_vector_new(count[i]);
11437 wvector[i] = cpl_vector_new(count[i]);
11438 }
11439 count[i] = 0;
11440 }
11441
11442
11443
11444
11445
11446
11447
11448 data = cpl_image_get_data(wavemap);
11449 sdata = cpl_image_get_data(spectra);
11450
11451 for (i = 0; i < npix; i++) {
11452 if (data[i] < 1.0)
11453 continue;
11454 bin = (data[i] - firstLambda) / dispersion;
11455 if (bin < nbin) {
11456 if (vector[bin]) {
11457 cpl_vector_set(vector[bin], count[bin], sdata[i]);
11458 cpl_vector_set(wvector[bin], count[bin], data[i]);
11459 }
11460 count[bin]++;
11461 }
11462 }
11463
11464
11465
11466
11467
11468
11469
11470 sky_spectrum = cpl_calloc(nbin, sizeof(double));
11471 sky_wave = cpl_calloc(nbin, sizeof(double));
11472 for (i = 0; i < nbin; i++) {
11473 if (vector[i]) {
11474 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
11475 sky_wave[i] = cpl_vector_get_median_const(wvector[i]);
11476 cpl_vector_delete(vector[i]);
11477 cpl_vector_delete(wvector[i]);
11478 }
11479 }
11480
11481 cpl_free(vector);
11482 cpl_free(wvector);
11483
11484
11485
11486
11487
11488
11489 for (i = 0; i < nbin; i++) {
11490 if (count[i] >= minpoints) {
11491 first_valid = i;
11492 break;
11493 }
11494 }
11495
11496 for (i = first_valid; i < nbin; i++) {
11497 if (count[i] < minpoints) {
11498 sky_wave[i] = firstLambda + (i+0.5)*dispersion;
11499 for (j = i+1; j < nbin; j++) {
11500 if (count[j] >= minpoints) {
11501 if (sky_wave[j] - sky_wave[i-1] < 0.1) {
11502 sky_spectrum[i] = (sky_spectrum[j] + sky_spectrum[i-1])
11503 / 2;
11504 }
11505 else {
11506 frac = (sky_wave[i] - sky_wave[i-1])
11507 / (sky_wave[j] - sky_wave[i-1]);
11508 sky_spectrum[i] = frac * sky_spectrum[j]
11509 + (1 - frac) * sky_spectrum[i-1];
11510 }
11511 }
11512 }
11513 }
11514 }
11515
11516
11517
11518
11519
11520
11521 sky = cpl_table_new(nbin);
11522 cpl_table_wrap_double(sky, sky_wave, "wavelength");
11523 cpl_table_wrap_double(sky, sky_spectrum, "sky");
11524 cpl_table_wrap_int(sky, count, "npoints");
11525
11526
11527
11528
11529
11530
11531 data = cpl_image_get_data(wavemap);
11532 sdata = cpl_image_get_data(spectra);
11533 kdata = cpl_image_get_data(skymap);
11534
11535 for (i = 0; i < npix; i++) {
11536
11537
11538
11539
11540
11541 lambda = data[i];
11542 if (lambda < 1.0)
11543 continue;
11544 bin = (lambda - firstLambda) / dispersion;
11545 lambda1 = sky_wave[bin];
11546 value1 = sky_spectrum[bin];
11547 if (lambda1 < lambda) {
11548 bin++;
11549 if (bin < nbin) {
11550 lambda2 = sky_wave[bin];
11551 value2 = sky_spectrum[bin];
11552 if (lambda2 - lambda1 < 0.1) {
11553 value = (value1 + value2) / 2;
11554 }
11555 else {
11556 frac = (lambda - lambda1) / (lambda2 - lambda1);
11557 value = frac * value2 + (1 - frac) * value1;
11558 }
11559 }
11560 else {
11561 value = value1;
11562 }
11563 }
11564 else {
11565 if (bin > 0) {
11566 bin--;
11567 lambda2 = lambda1;
11568 value2 = value1;
11569 lambda1 = sky_wave[bin];
11570 value1 = sky_spectrum[bin];
11571 if (lambda2 - lambda1 < 0.1) {
11572 value = (value1 + value2) / 2;
11573 }
11574 else {
11575 frac = (lambda - lambda1) / (lambda2 - lambda1);
11576 value = frac * value2 + (1 - frac) * value1;
11577 }
11578 }
11579 else {
11580 value = value1;
11581 }
11582 }
11583 kdata[i] = value;
11584 }
11585
11586 if (first_valid)
11587 cpl_table_erase_window(sky, 0, first_valid);
11588
11589 return sky;
11590
11591 }
11592
11593
11627 cpl_table *mos_sky_map(cpl_image *spectra, cpl_image *wavemap,
11628 double dispersion, cpl_image *skymap)
11629 {
11630 const char *func = "mos_sky_map";
11631
11632 cpl_vector **vector;
11633 double firstLambda, lastLambda;
11634 double lambda, lambda1, lambda2;
11635 double value, value1, value2;
11636 float min, max;
11637 int *count;
11638 int nbin, bin;
11639 int nx, ny, npix;
11640 int i, j;
11641
11642 cpl_table *sky;
11643 double *sky_spectrum;
11644 float *data;
11645 float *sdata;
11646 float *kdata;
11647 double *wdata;
11648
11649
11650 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
11651 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11652 return NULL;
11653 }
11654
11655 if (dispersion <= 0.0) {
11656 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11657 return NULL;
11658 }
11659
11660 nx = cpl_image_get_size_x(spectra);
11661 ny = cpl_image_get_size_y(spectra);
11662 npix = nx * ny;
11663
11664 if (nx != cpl_image_get_size_x(wavemap) ||
11665 ny != cpl_image_get_size_y(wavemap) ||
11666 nx != cpl_image_get_size_x(skymap) ||
11667 ny != cpl_image_get_size_y(skymap)) {
11668 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
11669 return NULL;
11670 }
11671
11672
11673
11674
11675
11676
11677 data = cpl_image_get_data(wavemap);
11678
11679 for (i = 0; i < npix; i++) {
11680 if (data[i] > 1.0) {
11681 min = max = data[i];
11682 j = i+1;
11683 break;
11684 }
11685 }
11686
11687 for (i = j; i < npix; i++) {
11688 if (data[i] < 1.0)
11689 continue;
11690 if (min > data[i])
11691 min = data[i];
11692 if (max < data[i])
11693 max = data[i];
11694 }
11695
11696 firstLambda = min;
11697 lastLambda = max;
11698
11699
11700
11701
11702
11703
11704 nbin = (lastLambda - firstLambda) / dispersion;
11705
11706
11707
11708
11709
11710
11711
11712
11713 count = cpl_calloc(nbin, sizeof(int));
11714
11715 data = cpl_image_get_data(wavemap);
11716
11717 for (i = 0; i < npix; i++) {
11718 if (data[i] < 1.0)
11719 continue;
11720 bin = (data[i] - firstLambda) / dispersion;
11721 if (bin < nbin)
11722 count[bin]++;
11723 }
11724
11725
11726
11727
11728
11729
11730
11731
11732
11733 vector = cpl_calloc(nbin, sizeof(cpl_vector *));
11734 for (i = 0; i < nbin; i++) {
11735 if (count[i])
11736 vector[i] = cpl_vector_new(count[i]);
11737 else
11738 vector[i] = NULL;
11739 count[i] = 0;
11740 }
11741
11742
11743
11744
11745
11746
11747
11748 data = cpl_image_get_data(wavemap);
11749 sdata = cpl_image_get_data(spectra);
11750
11751 for (i = 0; i < npix; i++) {
11752 if (data[i] < 1.0)
11753 continue;
11754 bin = (data[i] - firstLambda) / dispersion;
11755 if (bin < nbin) {
11756 cpl_vector_set(vector[bin], count[bin], sdata[i]);
11757 count[bin]++;
11758 }
11759 }
11760
11761
11762
11763
11764
11765
11766
11767 sky_spectrum = cpl_calloc(nbin, sizeof(double));
11768 for (i = 0; i < nbin; i++) {
11769 if (vector[i]) {
11770 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
11771 cpl_vector_delete(vector[i]);
11772 }
11773 }
11774
11775 cpl_free(vector);
11776
11777
11778
11779
11780
11781
11782
11783
11784
11785
11786
11787
11788
11789 sky = cpl_table_new(nbin);
11790 cpl_table_new_column(sky, "wavelength", CPL_TYPE_DOUBLE);
11791 cpl_table_set_column_unit(sky, "wavelength", "pixel");
11792 cpl_table_wrap_double(sky, sky_spectrum, "sky");
11793 cpl_table_wrap_int(sky, count, "npoints");
11794 for (i = 0; i < nbin; i++)
11795 cpl_table_set_double(sky, "wavelength", i,
11796 firstLambda + (i+0.5)*dispersion);
11797
11798
11799
11800
11801
11802
11803 data = cpl_image_get_data(wavemap);
11804 sdata = cpl_image_get_data(spectra);
11805 kdata = cpl_image_get_data(skymap);
11806 wdata = cpl_table_get_data_double(sky, "wavelength");
11807
11808 for (i = 0; i < npix; i++) {
11809
11810
11811
11812
11813
11814 lambda = data[i];
11815 if (lambda < 1.0)
11816 continue;
11817 bin = (lambda - firstLambda) / dispersion;
11818 lambda1 = wdata[bin];
11819 value1 = sky_spectrum[bin];
11820 if (lambda1 < lambda) {
11821 bin++;
11822 if (bin < nbin) {
11823 lambda2 = wdata[bin];
11824 value2 = sky_spectrum[bin];
11825 value = ((lambda2 - lambda)*value1
11826 + (lambda - lambda1)*value2) / dispersion;
11827 }
11828 else {
11829 value = value1;
11830 }
11831 }
11832 else {
11833 if (bin > 0) {
11834 bin--;
11835 lambda2 = lambda1;
11836 value2 = value1;
11837 lambda1 = wdata[bin];
11838 value1 = sky_spectrum[bin];
11839 value = ((lambda2 - lambda)*value1
11840 + (lambda - lambda1)*value2)/dispersion;
11841 }
11842 else {
11843 value = value1;
11844 }
11845 }
11846 kdata[i] = value;
11847 }
11848
11849 return sky;
11850
11851 }
11852
11853
11869 cpl_image *mos_sky_local_old(cpl_image *spectra, cpl_table *slits)
11870 {
11871 const char *func = "mos_sky_local_old";
11872
11873 cpl_image *exslit;
11874 cpl_image *sky;
11875 cpl_image *skymap;
11876 float *data;
11877 float *sdata;
11878 int nx, ny;
11879 int xlow, ylow, xhig, yhig;
11880 int nslits;
11881 int *slit_id;
11882 int *position;
11883 int *length;
11884 int i, j, k;
11885
11886
11887 if (spectra == NULL) {
11888 cpl_msg_error(func,
11889 "A scientific rectified spectral image must be given");
11890 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11891 return NULL;
11892 }
11893
11894 if (slits == NULL) {
11895 cpl_msg_error(func, "A slits position table must be given");
11896 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11897 return NULL;
11898 }
11899
11900 nslits = cpl_table_get_nrow(slits);
11901 slit_id = cpl_table_get_data_int(slits, "slit_id");
11902 position = cpl_table_get_data_int(slits, "position");
11903 length = cpl_table_get_data_int(slits, "length");
11904
11905 nx = cpl_image_get_size_x(spectra);
11906 ny = cpl_image_get_size_y(spectra);
11907
11908 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
11909
11910 xlow = 1;
11911 xhig = nx;
11912 for (i = 0; i < nslits; i++) {
11913
11914 if (length[i] == 0)
11915 continue;
11916
11917
11918
11919
11920
11921
11922
11923
11924
11925
11926
11927 ylow = position[i] + 1;
11928 yhig = ylow + length[i] - 1;
11929
11930 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
11931 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
11932 cpl_image_delete(exslit);
11933
11934 data = cpl_image_get_data(skymap);
11935 data += nx * position[i];
11936
11937 for (j = 0; j < length[i]; j++) {
11938 sdata = cpl_image_get_data(sky);
11939 for (k = 0; k < nx; k++) {
11940 *data++ = *sdata++;
11941 }
11942 }
11943
11944 cpl_image_delete(sky);
11945 }
11946
11947 return skymap;
11948
11949 }
11950
11951
11971 cpl_image *mos_sky_local(cpl_image *spectra, cpl_table *slits, int order)
11972 {
11973 const char *func = "mos_sky_local";
11974
11975 char name[MAX_COLNAME];
11976
11977 cpl_polynomial *fit;
11978 cpl_vector *points;
11979 cpl_vector *values;
11980 cpl_vector *keep_points;
11981 cpl_vector *keep_values;
11982 cpl_image *exslit;
11983 cpl_image *sky;
11984 cpl_image *subtracted;
11985 cpl_image *profile;
11986 cpl_image *skymap;
11987 cpl_table *objects;
11988 float *data;
11989 float *sdata;
11990 float *xdata;
11991 double *vdata;
11992 double *pdata;
11993 double median;
11994 int nx, ny;
11995 int xlow, ylow, xhig, yhig;
11996 int nslits;
11997 int *slit_id;
11998 int *position;
11999 int *length;
12000 int *is_sky;
12001 int nsky, nbad;
12002 int maxobjects;
12003 int margin = 3;
12004 int radius = 6;
12005 int i, j, k;
12006
12007
12008 if (spectra == NULL) {
12009 cpl_msg_error(func,
12010 "A scientific rectified spectral image must be given");
12011 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12012 return NULL;
12013 }
12014
12015 if (slits == NULL) {
12016 cpl_msg_error(func, "A slits position table must be given");
12017 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12018 return NULL;
12019 }
12020
12021 if (order < 0) {
12022 cpl_msg_error(func, "Invalid fit order");
12023 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12024 return NULL;
12025 }
12026
12027 nslits = cpl_table_get_nrow(slits);
12028 slit_id = cpl_table_get_data_int(slits, "slit_id");
12029 position = cpl_table_get_data_int(slits, "position");
12030 length = cpl_table_get_data_int(slits, "length");
12031
12032 nx = cpl_image_get_size_x(spectra);
12033 ny = cpl_image_get_size_y(spectra);
12034
12035 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12036
12037 xlow = 1;
12038 xhig = nx;
12039 for (i = 0; i < nslits; i++) {
12040
12041 if (length[i] == 0)
12042 continue;
12043
12044
12045
12046
12047
12048
12049
12050
12051
12052
12053
12054 ylow = position[i] + 1;
12055 yhig = ylow + length[i] - 1;
12056
12057 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
12058 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
12059 cpl_image_delete(exslit);
12060
12061 data = cpl_image_get_data(skymap);
12062 data += nx * position[i];
12063
12064 for (j = 0; j < length[i]; j++) {
12065 sdata = cpl_image_get_data(sky);
12066 for (k = 0; k < nx; k++) {
12067 *data++ = *sdata++;
12068 }
12069 }
12070
12071 cpl_image_delete(sky);
12072 }
12073
12074
12075
12076
12077
12078
12079 subtracted = cpl_image_duplicate(spectra);
12080 cpl_image_subtract(subtracted, skymap);
12081 cpl_image_delete(skymap);
12082
12083
12084
12085
12086
12087
12088 objects = cpl_table_duplicate(slits);
12089 profile = mos_detect_objects(subtracted, objects, margin, radius, 0);
12090 cpl_image_delete(profile);
12091 cpl_image_delete(subtracted);
12092
12093
12094
12095
12096
12097
12098
12099 maxobjects = 1;
12100 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
12101 while (cpl_table_has_column(objects, name)) {
12102 maxobjects++;
12103 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
12104 }
12105
12106 is_sky = cpl_calloc(ny, sizeof(int));
12107
12108 for (i = 0; i < nslits; i++) {
12109
12110 if (length[i] == 0)
12111 continue;
12112
12113 ylow = position[i] + margin;
12114 yhig = position[i] + length[i] - margin;
12115
12116 for (j = ylow; j < yhig; j++)
12117 is_sky[j] = 1;
12118
12119 for (j = 1; j < maxobjects; j++) {
12120 snprintf(name, MAX_COLNAME, "object_%d", j);
12121 if (cpl_table_is_valid(objects, name, i)) {
12122 snprintf(name, MAX_COLNAME, "start_%d", j);
12123 ylow = cpl_table_get_int(objects, name, i, NULL);
12124 snprintf(name, MAX_COLNAME, "end_%d", j);
12125 yhig = cpl_table_get_int(objects, name, i, NULL);
12126 for (k = ylow; k <= yhig; k++)
12127 is_sky[k] = 0;
12128 }
12129 }
12130
12131
12132
12133
12134
12135
12136 ylow = position[i] + margin + 1;
12137 yhig = position[i] + length[i] - margin - 1;
12138
12139 for (j = ylow; j < yhig; j++)
12140 if (is_sky[j])
12141 if (is_sky[j-1] == 0 && is_sky[j+1] == 0)
12142 is_sky[j] = 0;
12143
12144 }
12145
12146
12147
12148
12149
12150
12151 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12152
12153 for (i = 0; i < nslits; i++) {
12154
12155 if (length[i] == 0)
12156 continue;
12157
12158 ylow = position[i];
12159 yhig = ylow + length[i];
12160
12161 nsky = 0;
12162 for (j = ylow; j < yhig; j++)
12163 if (is_sky[j])
12164 nsky++;
12165
12166 if (nsky > order + 1) {
12167 if (order) {
12168 points = cpl_vector_new(nsky);
12169 nsky = 0;
12170 for (j = ylow; j < yhig; j++) {
12171 if (is_sky[j]) {
12172 cpl_vector_set(points, nsky, j);
12173 nsky++;
12174 }
12175 }
12176
12177 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
12178 xdata = cpl_image_get_data(exslit);
12179 values = cpl_vector_new(nsky);
12180
12181 for (j = 0; j < nx; j++) {
12182 nsky = 0;
12183 for (k = ylow; k < yhig; k++) {
12184 if (is_sky[k]) {
12185 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
12186 nsky++;
12187 }
12188 }
12189
12190
12191
12192
12193
12194 median = cpl_vector_get_median_const(values);
12195 vdata = cpl_vector_get_data(values);
12196 pdata = cpl_vector_get_data(points);
12197 nbad = 0;
12198 for (k = 0; k < nsky; k++) {
12199 if (fabs(vdata[k] - median) < 100) {
12200 if (nbad) {
12201 vdata[k-nbad] = vdata[k];
12202 pdata[k-nbad] = pdata[k];
12203 }
12204 }
12205 else
12206 nbad++;
12207 }
12208
12209 if (nsky == nbad)
12210 continue;
12211
12212 if (nbad && nsky - nbad > order + 1) {
12213 keep_values = values;
12214 keep_points = points;
12215 values = cpl_vector_wrap(nsky-nbad, vdata);
12216 points = cpl_vector_wrap(nsky-nbad, pdata);
12217 }
12218
12219 if (nsky - nbad > order + 1) {
12220
12221 fit = cpl_polynomial_fit_1d_create(points, values,
12222 order, NULL);
12223
12224 if (fit) {
12225 for (k = ylow; k < yhig; k++) {
12226 xdata[j+(k-ylow)*nx] =
12227 cpl_polynomial_eval_1d(fit, k, NULL);
12228 }
12229
12230 cpl_polynomial_delete(fit);
12231 }
12232 else
12233 cpl_error_reset();
12234 }
12235 else {
12236 for (k = 0; k < nsky; k++) {
12237 xdata[j+k*nx] = median;
12238 }
12239 }
12240
12241 if (nbad && nsky - nbad > order + 1) {
12242 cpl_vector_unwrap(values);
12243 cpl_vector_unwrap(points);
12244 values = keep_values;
12245 points = keep_points;
12246 }
12247
12248 if (nbad) {
12249 nsky = 0;
12250 for (k = ylow; k < yhig; k++) {
12251 if (is_sky[k]) {
12252 cpl_vector_set(points, nsky, k);
12253 nsky++;
12254 }
12255 }
12256 }
12257
12258 }
12259
12260 cpl_vector_delete(values);
12261 cpl_vector_delete(points);
12262
12263 cpl_image_copy(skymap, exslit, 1, ylow+1);
12264 cpl_image_delete(exslit);
12265
12266 }
12267 else {
12268 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
12269 xdata = cpl_image_get_data(exslit);
12270 values = cpl_vector_new(nsky);
12271
12272 for (j = 0; j < nx; j++) {
12273 nsky = 0;
12274 for (k = ylow; k < yhig; k++) {
12275 if (is_sky[k]) {
12276 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
12277 nsky++;
12278 }
12279 }
12280
12281 median = cpl_vector_get_median_const(values);
12282
12283 for (k = ylow; k < yhig; k++)
12284 xdata[j+(k-ylow)*nx] = median;
12285
12286 }
12287
12288 cpl_vector_delete(values);
12289
12290 cpl_image_copy(skymap, exslit, 1, ylow+1);
12291 cpl_image_delete(exslit);
12292 }
12293 }
12294 else
12295 cpl_msg_warning(func, "Too few sky points in slit %d", i + 1);
12296 }
12297
12298 cpl_free(is_sky);
12299
12300 return skymap;
12301
12302 }
12303
12304
12326 cpl_error_code mos_clean_cosmics(cpl_image *image, float gain,
12327 float threshold, float ratio)
12328 {
12329 const char *func = "mos_clean_cosmics";
12330
12331 cpl_image *smoothImage;
12332 cpl_table *table;
12333 cpl_matrix *kernel;
12334 int *xdata;
12335 int *ydata;
12336 float *idata;
12337 float *sdata;
12338 float sigma, sum, value, smoothValue;
12339 double noise;
12340 int count;
12341 float fMax;
12342 int iMin, iMax, jMin, jMax, iPosMax, jPosMax;
12343 int xLen;
12344 int yLen;
12345 int nPix;
12346 int first = 1;
12347
12348 int pos, i, j, k, l, ii, jj, iii = 0, jjj = 0;
12349 int numCosmic = 0;
12350 int found, foundContiguousCandidate;
12351 int *cosmic;
12352
12353
12354 if (image == NULL)
12355 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12356
12357
12358
12359
12360
12361
12362
12363
12364
12365
12366
12367
12368 xLen = cpl_image_get_size_x(image);
12369 yLen = cpl_image_get_size_y(image);
12370
12371 if (xLen < 4 || yLen < 4)
12372 return CPL_ERROR_NONE;
12373
12374 nPix = xLen * yLen;
12375
12376
12377
12378
12379
12380
12381
12382
12383
12384
12385
12386
12387
12388
12389
12390
12391
12392
12393
12394
12395
12396
12397 idata = cpl_image_get_data(image);
12398 noise = 0.0;
12399 count = 0;
12400
12401 for (i = 0; i < nPix; i++) {
12402 if (idata[i] < -0.00001) {
12403 noise -= idata[i];
12404 count++;
12405 }
12406 }
12407
12408 noise /= count;
12409 noise *= 1.25;
12410
12411 cosmic = cpl_calloc(nPix, sizeof(int));
12412
12413 if (threshold < 0.)
12414 threshold = 4.0;
12415 if (ratio < 0.)
12416 ratio = 2.0;
12417
12418 kernel = cpl_matrix_new(3, 3);
12419 cpl_matrix_fill(kernel, 1.0);
12420 cpl_matrix_set(kernel, 1, 1, 0.0);
12421 smoothImage = cpl_image_filter_median(image, kernel);
12422 cpl_matrix_delete(kernel);
12423
12424
12425
12426
12427
12428
12429
12430
12431
12432
12433 sdata = cpl_image_get_data(smoothImage);
12434
12435 for (j = 1; j < yLen - 1; j++) {
12436 for (i = 1; i < xLen - 1; i++) {
12437 value = idata[i + j * xLen];
12438 smoothValue = sdata[i + j * xLen];
12439 if (smoothValue < 1.0)
12440 smoothValue = 1.0;
12441 sigma = sqrt(noise * noise + smoothValue / gain);
12442 if (value - smoothValue >= threshold * sigma)
12443 cosmic[i + j * xLen] = -1;
12444 }
12445 }
12446
12447 cpl_image_delete(smoothImage);
12448
12449
12450
12451
12452
12453
12454 do {
12455 found = 0;
12456 for (pos = first; pos < nPix; pos++) {
12457 if (cosmic[pos] == -1) {
12458 cosmic[pos] = 2;
12459 i = pos % xLen;
12460 j = pos / xLen;
12461 first = pos;
12462 first++;
12463 found = 1;
12464 break;
12465 }
12466 }
12467
12468 if (found) {
12469
12470
12471
12472
12473
12474
12475
12476
12477 iMin = iMax = iPosMax = i;
12478 jMin = jMax = jPosMax = j;
12479 fMax = idata[i + j * xLen];
12480
12481 do {
12482 foundContiguousCandidate = 0;
12483 for (l = 0; l <= 1; l++) {
12484 for (k = 0; k <= 1; k++) {
12485
12486
12487
12488
12489
12490 ii = i + k - l;
12491 jj = j + k + l - 1;
12492 if (cosmic[ii + jj * xLen] == -1) {
12493 foundContiguousCandidate = 1;
12494 cosmic[ii + jj * xLen] = 2;
12495
12496 iii = ii;
12497 jjj = jj;
12498
12499
12500
12501
12502
12503 if (ii < iMin)
12504 iMin = ii;
12505 if (ii > iMax)
12506 iMax = ii;
12507 if (jj < jMin)
12508 jMin = jj;
12509 if (jj > jMax)
12510 jMax = jj;
12511
12512 if (idata[ii + jj * xLen] > fMax) {
12513 fMax = idata[ii + jj * xLen];
12514 iPosMax = ii;
12515 jPosMax = jj;
12516 }
12517 }
12518 }
12519 }
12520
12521
12522
12523
12524
12525
12526 cosmic[i + j * xLen] = 3;
12527
12528 if (foundContiguousCandidate) {
12529
12530
12531
12532
12533
12534
12535 i = iii;
12536 j = jjj;
12537
12538
12539
12540
12541
12542 continue;
12543 }
12544
12545
12546
12547
12548
12549
12550 for (l = jMin; l <= jMax; l++) {
12551 for (k = iMin; k <= iMax; k++) {
12552 if (cosmic[k + l * xLen] == 2) {
12553 i = k;
12554 j = l;
12555 foundContiguousCandidate = 1;
12556 break;
12557 }
12558 }
12559 if (foundContiguousCandidate)
12560 break;
12561 }
12562 } while (foundContiguousCandidate);
12563
12564
12565
12566
12567
12568
12569
12570 sum = 0.;
12571 for (l = -1; l <= 1; l++) {
12572 for (k = -1; k <= 1; k++) {
12573 if (l != 0 || k != 0) {
12574 sum += idata[iPosMax + k + (jPosMax + l) * xLen];
12575 }
12576 }
12577 }
12578
12579 sum /= 8.;
12580 if (fMax > ratio * sum) {
12581 for (l = jMin - 1; l <= jMax + 1; l++) {
12582 for (k = iMin - 1; k <= iMax + 1; k++) {
12583 if (cosmic[k + l * xLen] == 3) {
12584 cosmic[k + l * xLen] = 1;
12585 numCosmic++;
12586 }
12587 }
12588 }
12589 }
12590 else {
12591 for (l = jMin - 1; l <= jMax + 1; l++) {
12592 for (k = iMin - 1; k <= iMax + 1; k++) {
12593 if (cosmic[k + l * xLen] != -1) {
12594 if (cosmic[k + l * xLen] == 1)
12595 numCosmic--;
12596 cosmic[k + l * xLen] = 0;
12597 }
12598 }
12599 }
12600 }
12601 }
12602 } while (found);
12603
12604
12605
12606
12607
12608
12609 table = cpl_table_new(numCosmic);
12610 cpl_table_new_column(table, "x", CPL_TYPE_INT);
12611 cpl_table_new_column(table, "y", CPL_TYPE_INT);
12612 cpl_table_set_column_unit(table, "x", "pixel");
12613 cpl_table_set_column_unit(table, "y", "pixel");
12614 xdata = cpl_table_get_data_int(table, "x");
12615 ydata = cpl_table_get_data_int(table, "y");
12616
12617 for (pos = 0, i = 0; pos < nPix; pos++) {
12618 if (cosmic[pos] == 1) {
12619 xdata[i] = (pos % xLen);
12620 ydata[i] = (pos / xLen);
12621 i++;
12622 }
12623 }
12624
12625 mos_clean_bad_pixels(image, table, 1);
12626
12627 cpl_free(cosmic);
12628 cpl_table_delete(table);
12629
12630 return CPL_ERROR_NONE;
12631
12632 }
12633
12634
12635 cpl_error_code mos_clean_bad_pixels(cpl_image *image, cpl_table *table,
12636 int spectral)
12637 {
12638 const char *func = "mos_clean_cosmics";
12639
12640 float *idata;
12641 int *isBadPix;
12642 int i, j, k, d;
12643 int xlen, ylen, totPix;
12644 int nBadPixels = 0;
12645 int sign, foundFirst;
12646 int *xValue = NULL;
12647 int *yValue = NULL;
12648 float save = 0.;
12649 double sumd;
12650 int cx, cy;
12651 int nPairs;
12652 float estimate[4];
12653 int sx[] = {0, 1, 1, 1};
12654 int sy[] = {1,-1, 0, 1};
12655 int searchHorizon = 100;
12656 int percent = 15;
12657
12658
12659 if (image == NULL || table == NULL)
12660 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12661
12662 if (1 != cpl_table_has_column(table, "x"))
12663 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
12664
12665 if (1 != cpl_table_has_column(table, "y"))
12666 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
12667
12668 if (CPL_TYPE_INT != cpl_table_get_column_type(table, "x"))
12669 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
12670
12671 if (CPL_TYPE_INT != cpl_table_get_column_type(table, "y"))
12672 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
12673
12674 nBadPixels = cpl_table_get_nrow(table);
12675
12676 if (nBadPixels) {
12677 xlen = cpl_image_get_size_x(image);
12678 ylen = cpl_image_get_size_y(image);
12679 idata = cpl_image_get_data(image);
12680 totPix = xlen * ylen;
12681 if (((float) nBadPixels) / ((float) totPix) < percent/100.) {
12682 isBadPix = cpl_calloc(totPix, sizeof(int));
12683 }
12684 else {
12685 cpl_msg_warning(func, "Too many bad pixels (> %d%%): "
12686 "skip bad pixel correction", percent);
12687 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12688 }
12689 }
12690 else {
12691 cpl_msg_debug(func, "No pixel values to interpolate");
12692 return CPL_ERROR_NONE;
12693 }
12694
12695 xValue = cpl_table_get_data_int(table, "x");
12696 yValue = cpl_table_get_data_int(table, "y");
12697
12698 for (i = 0; i < nBadPixels; i++)
12699 isBadPix[xValue[i] + yValue[i] * xlen] = 1;
12700
12701 for (i = 0; i < nBadPixels; i++) {
12702
12703
12704
12705
12706
12707
12708
12709
12710
12711
12712
12713
12714
12715 nPairs = 0;
12716 for (j = 0; j < 4; j++) {
12717
12718 if (spectral)
12719 if (j != 2)
12720 continue;
12721
12722 estimate[nPairs] = 0.;
12723 sumd = 0.;
12724 foundFirst = 0;
12725 for (k = 0; k < 2; k++) {
12726 sign = 2 * k - 1;
12727 d = 0;
12728 cx = xValue[i];
12729 cy = yValue[i];
12730 do {
12731 cx += sign * sx[j];
12732 cy += sign * sy[j];
12733 if (cx < 0 || cx >= xlen || cy < 0 || cy >= ylen)
12734 break;
12735 d++;
12736 } while (isBadPix[cx + cy * xlen] && d < searchHorizon);
12737
12738 if (cx >= 0 && cx < xlen &&
12739 cy >= 0 && cy < ylen && d < searchHorizon) {
12740
12741
12742
12743
12744
12745 save = idata[cx + cy * xlen];
12746 estimate[nPairs] += save / d;
12747 sumd += 1. / (double) d;
12748 if (k) {
12749 estimate[nPairs] /= sumd;
12750 nPairs++;
12751 }
12752 else {
12753 foundFirst = 1;
12754 }
12755 }
12756 else {
12757
12758
12759
12760
12761
12762 if (k) {
12763 if (foundFirst) {
12764 estimate[nPairs] = save;
12765 nPairs++;
12766 }
12767 }
12768 }
12769 }
12770 }
12771
12772
12773
12774
12775
12776
12777
12778 if (nPairs > 2) {
12779 idata[xValue[i] + yValue[i] * xlen] =
12780 cpl_tools_get_median_float(estimate, nPairs);
12781 }
12782 else if (nPairs == 2) {
12783 idata[xValue[i] + yValue[i] * xlen] =
12784 (estimate[0] + estimate[1]) / 2.;
12785 }
12786 else if (nPairs == 1) {
12787 idata[xValue[i] + yValue[i] * xlen] = estimate[0];
12788 }
12789 else {
12790 cpl_msg_debug(func, "Cannot correct bad pixel %d,%d\n",
12791 xValue[i], yValue[i]);
12792 }
12793 }
12794
12795 cpl_free(isBadPix);
12796
12797 return CPL_ERROR_NONE;
12798 }
12799
12800
12830 cpl_image *mos_spatial_map(cpl_image *spectra, cpl_table *slits,
12831 cpl_table *polytraces, double reference,
12832 double blue, double red, double dispersion)
12833 {
12834 const char *func = "mos_spatial_map";
12835
12836 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
12837
12838 cpl_polynomial *polytop;
12839 cpl_polynomial *polybot;
12840 cpl_image *calibration;
12841 float *data;
12842 double top, bot;
12843 double coeff;
12844 double ytop, ybot;
12845 double ypos, yfra;
12846 double factor;
12847 int yint, yprev;
12848 int nslits;
12849 int npseudo;
12850 int *slit_id;
12851 int *length;
12852 int nx, ny;
12853 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
12854 int missing_top, missing_bot;
12855 int null;
12856 int order;
12857 int i, j, k;
12858
12859
12860 if (spectra == NULL || slits == NULL || polytraces == NULL) {
12861 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12862 return NULL;
12863 }
12864
12865 if (dispersion <= 0.0) {
12866 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12867 return NULL;
12868 }
12869
12870 if (red - blue < dispersion) {
12871 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12872 return NULL;
12873 }
12874
12875 nx = cpl_image_get_size_x(spectra);
12876 ny = cpl_image_get_size_y(spectra);
12877
12878 calibration = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12879 data = cpl_image_get_data(calibration);
12880
12881 length = cpl_table_get_data_int(slits, "length");
12882 nslits = cpl_table_get_nrow(slits);
12883 slit_id = cpl_table_get_data_int(slits, "slit_id");
12884 order = cpl_table_get_ncol(polytraces) - 2;
12885
12886
12887
12888
12889
12890
12891 pixel_above = (red - reference) / dispersion;
12892 pixel_below = (reference - blue) / dispersion;
12893
12894 for (i = 0; i < nslits; i++) {
12895
12896 if (length[i] == 0)
12897 continue;
12898
12899
12900
12901
12902
12903
12904
12905
12906
12907
12908
12909
12910 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
12911
12912 start_pixel = refpixel - pixel_below;
12913 if (start_pixel < 0)
12914 start_pixel = 0;
12915
12916 end_pixel = refpixel + pixel_above;
12917 if (end_pixel > nx)
12918 end_pixel = nx;
12919
12920
12921
12922
12923
12924
12925 missing_top = 0;
12926 polytop = cpl_polynomial_new(1);
12927 for (k = 0; k <= order; k++) {
12928 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
12929 if (null) {
12930 cpl_polynomial_delete(polytop);
12931 missing_top = 1;
12932 break;
12933 }
12934 cpl_polynomial_set_coeff(polytop, &k, coeff);
12935 }
12936
12937 missing_bot = 0;
12938 polybot = cpl_polynomial_new(1);
12939 for (k = 0; k <= order; k++) {
12940 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
12941 if (null) {
12942 cpl_polynomial_delete(polybot);
12943 missing_bot = 1;
12944 break;
12945 }
12946 cpl_polynomial_set_coeff(polybot, &k, coeff);
12947 }
12948
12949 if (missing_top && missing_bot) {
12950 cpl_msg_warning(func, "Spatial map, slit %d was not traced!",
12951 slit_id[i]);
12952 continue;
12953 }
12954
12955
12956
12957
12958
12959
12960
12961 if (missing_top) {
12962 cpl_msg_warning(func, "Upper edge of slit %d was not traced: "
12963 "the spectral curvature of the lower edge "
12964 "is used instead.", slit_id[i]);
12965 polytop = cpl_polynomial_duplicate(polybot);
12966 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
12967 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
12968 k = 0;
12969 coeff = cpl_polynomial_get_coeff(polybot, &k);
12970 coeff += ytop - ybot;
12971 cpl_polynomial_set_coeff(polytop, &k, coeff);
12972 }
12973
12974 if (missing_bot) {
12975 cpl_msg_warning(func, "Lower edge of slit %d was not traced: "
12976 "the spectral curvature of the upper edge "
12977 "is used instead.", slit_id[i]);
12978 polybot = cpl_polynomial_duplicate(polytop);
12979 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
12980 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
12981 k = 0;
12982 coeff = cpl_polynomial_get_coeff(polytop, &k);
12983 coeff -= ytop - ybot;
12984 cpl_polynomial_set_coeff(polybot, &k, coeff);
12985 }
12986
12987 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
12988 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
12989 npseudo = ceil(top-bot) + 1;
12990
12991 if (npseudo < 1) {
12992 cpl_polynomial_delete(polytop);
12993 cpl_polynomial_delete(polybot);
12994 cpl_msg_warning(func, "Slit %d was badly traced: no extraction!",
12995 slit_id[i]);
12996 continue;
12997 }
12998
12999 for (j = start_pixel; j < end_pixel; j++) {
13000 top = cpl_polynomial_eval_1d(polytop, j, NULL);
13001 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
13002 factor = (top-bot)/npseudo;
13003 for (k = 0; k <= npseudo; k++) {
13004 ypos = top - k*factor;
13005 yint = ypos;
13006 yfra = ypos - yint;
13007 if (yint >= 0 && yint < ny-1) {
13008 data[j + nx*yint] = (top-yint)/factor;
13009 if (k) {
13010
13011
13012
13013
13014
13015
13016
13017 if (yprev - yint > 1) {
13018 data[j + nx*(yint+1)] = (top-yint-1)/factor;
13019 }
13020 }
13021 }
13022 yprev = yint;
13023 }
13024 }
13025 cpl_polynomial_delete(polytop);
13026 cpl_polynomial_delete(polybot);
13027 }
13028
13029 return calibration;
13030 }
13031
13032
13095 cpl_image *mos_detect_objects(cpl_image *image, cpl_table *slits, int margin,
13096 int maxradius, int conradius)
13097 {
13098 const char *func = "mos_detect_objects";
13099
13100 cpl_image *profile;
13101 float *pdata;
13102 float *p;
13103
13104 char name[MAX_COLNAME];
13105
13106 int nslits;
13107 int npeaks;
13108 int nobjects, objpos, totobj;
13109 int maxobjects;
13110 int *position;
13111 int *length;
13112 int *reject;
13113 double *place;
13114 double *bright;
13115 double mindistance;
13116 int pos, count;
13117 int up;
13118 int low, hig;
13119 int row;
13120 int i, j, k;
13121
13122 const int min_pixels = 10;
13123
13124
13125 if (cpl_error_get_code() != CPL_ERROR_NONE)
13126 return NULL;
13127
13128 if (image == NULL || slits == NULL) {
13129 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13130 return NULL;
13131 }
13132
13133 if (margin < 0)
13134 margin = 0;
13135
13136 if (maxradius < 0) {
13137 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13138 return NULL;
13139 }
13140
13141 if (conradius < 0) {
13142 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13143 return NULL;
13144 }
13145
13146 nslits = cpl_table_get_nrow(slits);
13147 position = cpl_table_get_data_int(slits, "position");
13148 length = cpl_table_get_data_int(slits, "length");
13149
13150 profile = cpl_image_collapse_create(image, 1);
13151 cpl_image_divide_scalar(profile, cpl_image_get_size_x(image));
13152 pdata = cpl_image_get_data(profile);
13153
13154 row = 1;
13155 maxobjects = 0;
13156 totobj = 0;
13157 for (i = 0; i < nslits; i++) {
13158
13159 if (length[i] == 0)
13160 continue;
13161
13162 pos = position[i] + margin;
13163 count = length[i] - 2*margin;
13164
13165 if (count < min_pixels)
13166 continue;
13167
13168 p = pdata + pos;
13169
13170
13171
13172
13173
13174
13175 npeaks = 0;
13176 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
13177 npeaks++;
13178 }
13179
13180 up = 0;
13181 for (j = 0; j < count - 3; j++) {
13182 if (p[j] > 0) {
13183 if (p[j+1] > p[j]) {
13184 up++;
13185 }
13186 else {
13187 if (up > 2) {
13188 if (p[j+1] > p[j+2] && p[j+2] > 0) {
13189 if (p[j] > 5)
13190 npeaks++;
13191 }
13192 }
13193 else if (up > 1) {
13194 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
13195 if (p[j] > 5)
13196 npeaks++;
13197 }
13198 }
13199 up = 0;
13200 }
13201 }
13202 else {
13203 up = 0;
13204 }
13205 }
13206
13207 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
13208 && p[count-3] > p[count-4] && p[count-4] > 0) {
13209 npeaks++;
13210 }
13211
13212 if (npeaks == 0)
13213 continue;
13214
13215
13216
13217
13218
13219
13220 reject = cpl_calloc(npeaks, sizeof(int));
13221 bright = cpl_calloc(npeaks, sizeof(double));
13222 place = cpl_calloc(npeaks, sizeof(double));
13223
13224 npeaks = 0;
13225 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
13226 bright[0] = p[0];
13227 place[0] = position[i] + margin;
13228 npeaks++;
13229 }
13230
13231 up = 0;
13232 for (j = 0; j < count - 3; j++) {
13233 if (p[j] > 0) {
13234 if (p[j+1] > p[j]) {
13235 up++;
13236 }
13237 else {
13238 if (up > 2) {
13239 if (p[j+1] > p[j+2] && p[j+2] > 0) {
13240 if (p[j] > 5) {
13241 bright[npeaks] = p[j];
13242 place[npeaks] = position[i] + margin + j + 1
13243 + values_to_dx(p[j-1], p[j], p[j+1]);
13244 npeaks++;
13245 }
13246 }
13247 }
13248 else if (up > 1) {
13249 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
13250 if (p[j] > 5) {
13251 bright[npeaks] = p[j];
13252 place[npeaks] = position[i] + margin + j + 1
13253 + values_to_dx(p[j-1], p[j], p[j+1]);
13254 npeaks++;
13255 }
13256 }
13257 }
13258 up = 0;
13259 }
13260 }
13261 else {
13262 up = 0;
13263 }
13264 }
13265
13266 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
13267 && p[count-3] > p[count-4] && p[count-4] > 0) {
13268 bright[npeaks] = p[count-1];
13269 place[npeaks] = position[i] + count;
13270 npeaks++;
13271 }
13272
13273
13274
13275
13276
13277
13278 if (fabs(place[0] - pos) < 1.0)
13279 reject[0] = 1;
13280 if (fabs(place[npeaks-1] - pos - count) < 1.0)
13281 reject[npeaks-1] = 1;
13282 for (j = 0; j < npeaks; j++) {
13283 for (k = 0; k < npeaks; k++) {
13284 if (k == j)
13285 continue;
13286 mindistance = conradius * bright[k] / bright[j]
13287 * bright[k] / bright[j];
13288 if (fabs(place[j] - place[k]) < mindistance)
13289 reject[j] = 1;
13290 }
13291 }
13292
13293
13294 for (j = 0; j < npeaks; j++) {
13295 if (reject[j])
13296 continue;
13297 if (j) {
13298 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
13299 / (bright[j-1] + bright[j]) + 1;
13300 }
13301 else {
13302 low = pos;
13303 }
13304 if (j < npeaks - 1) {
13305 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
13306 / (bright[j+1] + bright[j]) + 1;
13307 }
13308 else {
13309 hig = pos + count;
13310 }
13311
13312 if (low < pos)
13313 low = pos;
13314 if (hig > pos + count)
13315 hig = pos + count;
13316 if (place[j] - low > maxradius)
13317 low = place[j] - maxradius;
13318 if (hig - place[j] > maxradius)
13319 hig = place[j] + maxradius;
13320 if (hig == low)
13321 reject[j] = 1;
13322 }
13323
13324
13325 nobjects = npeaks;
13326 for (j = 0; j < npeaks; j++)
13327 if (reject[j])
13328 nobjects--;
13329
13330 for (j = 0; j < nobjects; j++) {
13331 snprintf(name, MAX_COLNAME, "object_%d", j+1);
13332 if (cpl_table_has_column(slits, name))
13333 continue;
13334 cpl_table_new_column(slits, name, CPL_TYPE_DOUBLE);
13335 snprintf(name, MAX_COLNAME, "start_%d", j+1);
13336 cpl_table_new_column(slits, name, CPL_TYPE_INT);
13337 cpl_table_set_column_unit(slits, name, "pixel");
13338 snprintf(name, MAX_COLNAME, "end_%d", j+1);
13339 cpl_table_new_column(slits, name, CPL_TYPE_INT);
13340 cpl_table_set_column_unit(slits, name, "pixel");
13341 snprintf(name, MAX_COLNAME, "row_%d", j+1);
13342 cpl_table_new_column(slits, name, CPL_TYPE_INT);
13343 cpl_table_set_column_unit(slits, name, "pixel");
13344 }
13345
13346 objpos = nobjects;
13347 for (j = 0; j < npeaks; j++) {
13348 if (reject[j])
13349 continue;
13350 if (j) {
13351 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
13352 / (bright[j-1] + bright[j]) + 1;
13353 }
13354 else {
13355 low = pos;
13356 }
13357 if (j < npeaks - 1) {
13358 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
13359 / (bright[j+1] + bright[j]) + 1;
13360 }
13361 else {
13362 hig = pos + count;
13363 }
13364
13365 if (low < pos)
13366 low = pos;
13367 if (hig > pos + count)
13368 hig = pos + count;
13369 if (place[j] - low > maxradius)
13370 low = place[j] - maxradius;
13371 if (hig - place[j] > maxradius)
13372 hig = place[j] + maxradius;
13373
13374 snprintf(name, MAX_COLNAME, "object_%d", objpos);
13375 cpl_table_set_double(slits, name, i, place[j]);
13376 snprintf(name, MAX_COLNAME, "start_%d", objpos);
13377 cpl_table_set_int(slits, name, i, low);
13378 snprintf(name, MAX_COLNAME, "end_%d", objpos);
13379 cpl_table_set_int(slits, name, i, hig);
13380 snprintf(name, MAX_COLNAME, "row_%d", objpos);
13381 cpl_table_set_int(slits, name, i, row + objpos - 1);
13382 totobj++;
13383 objpos--;
13384 }
13385
13386 row += nobjects;
13387
13388 if (maxobjects < nobjects)
13389 maxobjects = nobjects;
13390
13391 cpl_free(reject);
13392 cpl_free(bright);
13393 cpl_free(place);
13394
13395 }
13396
13397
13398 row = cpl_table_get_nrow(slits);
13399
13400 for (i = 0; i < row; i++) {
13401 for (j = 0; j < maxobjects; j++) {
13402 snprintf(name, MAX_COLNAME, "row_%d", j+1);
13403 if (cpl_table_is_valid(slits, name, i))
13404 cpl_table_set_int(slits, name, i, totobj -
13405 cpl_table_get_int(slits, name, i, NULL));
13406 }
13407 }
13408
13409 for (i = 0; i < maxobjects; i++) {
13410 snprintf(name, MAX_COLNAME, "start_%d", i+1);
13411 cpl_table_fill_invalid_int(slits, name, -1);
13412 snprintf(name, MAX_COLNAME, "end_%d", i+1);
13413 cpl_table_fill_invalid_int(slits, name, -1);
13414 snprintf(name, MAX_COLNAME, "row_%d", i+1);
13415 cpl_table_fill_invalid_int(slits, name, -1);
13416 }
13417
13418 return profile;
13419 }
13420
13421
13446 cpl_image **mos_extract_objects(cpl_image *science, cpl_image *sky,
13447 cpl_table *objects, int extraction, double ron,
13448 double gain, int ncombined)
13449 {
13450 const char *func = "mos_extract_objects";
13451
13452 char name[MAX_COLNAME];
13453
13454 cpl_image **output;
13455 cpl_image *extracted;
13456 cpl_image *extr_sky;
13457 cpl_image *error;
13458 cpl_image *sciwin;
13459 cpl_image *skywin;
13460 int nslits;
13461 int nobjects;
13462 int maxobjects;
13463 int nx, ny;
13464 int ylow, yhig;
13465 int i, j;
13466
13467
13468 if (science == NULL || sky == NULL) {
13469 cpl_msg_error(func, "Both scientific exposures are required in input");
13470 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13471 return NULL;
13472 }
13473
13474 if (objects == NULL) {
13475 cpl_msg_error(func, "An object table is required in input");
13476 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13477 return NULL;
13478 }
13479
13480 if (extraction < 0 || extraction > 1) {
13481 cpl_msg_error(func, "Invalid extraction mode (%d): it should be "
13482 "either 0 or 1", extraction);
13483 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13484 return NULL;
13485 }
13486
13487 if (ron < 0.0) {
13488 cpl_msg_error(func, "Invalid read-out-noise (%f ADU)", ron);
13489 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13490 return NULL;
13491 }
13492
13493 if (gain < 0.1) {
13494 cpl_msg_error(func, "Invalid gain factor (%f e-/ADU)", gain);
13495 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13496 return NULL;
13497 }
13498
13499 if (ncombined < 1) {
13500 cpl_msg_error(func, "Invalid number of combined frames (%d): "
13501 "it should be at least 1", ncombined);
13502 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13503 return NULL;
13504 }
13505
13506
13507
13508
13509
13510
13511
13512 maxobjects = 1;
13513 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
13514 while (cpl_table_has_column(objects, name)) {
13515 maxobjects++;
13516 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
13517 }
13518
13519
13520
13521
13522
13523
13524 nobjects = 0;
13525 nslits = cpl_table_get_nrow(objects);
13526
13527 for (i = 0; i < nslits; i++) {
13528 for (j = 1; j < maxobjects; j++) {
13529 snprintf(name, MAX_COLNAME, "object_%d", j);
13530 if (cpl_table_is_valid(objects, name, i))
13531 nobjects++;
13532 }
13533 }
13534
13535 if (nobjects == 0)
13536 return NULL;
13537
13538 nx = cpl_image_get_size_x(science);
13539 ny = cpl_image_get_size_x(science);
13540
13541 output = cpl_calloc(3, sizeof(cpl_image *));
13542 extracted = output[0] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
13543 extr_sky = output[1] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
13544 error = output[2] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
13545
13546
13547
13548
13549
13550
13551 nobjects = 0;
13552 for (i = 0; i < nslits; i++) {
13553 for (j = 1; j < maxobjects; j++) {
13554 snprintf(name, MAX_COLNAME, "object_%d", j);
13555 if (cpl_table_is_valid(objects, name, i)) {
13556 snprintf(name, MAX_COLNAME, "start_%d", j);
13557 ylow = cpl_table_get_int(objects, name, i, NULL);
13558 snprintf(name, MAX_COLNAME, "end_%d", j);
13559 yhig = cpl_table_get_int(objects, name, i, NULL);
13560 snprintf(name, MAX_COLNAME, "row_%d", j);
13561 nobjects = cpl_table_get_int(objects, name, i, NULL);
13562 sciwin = cpl_image_extract(science, 1, ylow+1, nx, yhig);
13563 skywin = cpl_image_extract(sky, 1, ylow+1, nx, yhig);
13564
13565
13566
13567
13568
13569
13570
13571
13572 mos_extraction(sciwin, skywin, extracted, extr_sky, error,
13573 nobjects, extraction, ron, gain, ncombined);
13574 cpl_image_delete(sciwin);
13575 cpl_image_delete(skywin);
13576 nobjects++;
13577 }
13578 }
13579 }
13580
13581 return output;
13582
13583 }
13584
13585
13608 int mos_spectral_resolution(cpl_image *image, double lambda, double startwave,
13609 double dispersion, int saturation,
13610 double *mfwhm, double *rmsfwhm,
13611 double *resolution, double *rmsres, int *nlines)
13612 {
13613 cpl_vector *vector;
13614
13615 int i, j, n, m;
13616 int position, maxpos;
13617 int xlen, ylen;
13618 int sp, ep;
13619 int radius;
13620 int sradius = 40;
13621 int threshold = 250;
13622
13623 int ifwhm;
13624 double fwhm;
13625 double *buffer;
13626 double min, max, halfmax;
13627 double cut = 1.5;
13628 double value, rms;
13629
13630 float *data;
13631
13632
13633 *resolution = 0.0;
13634 *rmsres = 0.0;
13635 *nlines = 0;
13636
13637 xlen = cpl_image_get_size_x(image);
13638 ylen = cpl_image_get_size_y(image);
13639 data = cpl_image_get_data(image);
13640
13641 buffer = cpl_malloc(ylen * sizeof(double));
13642
13643
13644
13645
13646
13647 position = floor((lambda - startwave) / dispersion + 0.5);
13648
13649 sp = position - sradius;
13650 ep = position + sradius;
13651
13652 if (sp < 0 || ep > xlen) {
13653 cpl_free(buffer);
13654 return 0;
13655 }
13656
13657 for (i = 0, n = 0; i < ylen; i++) {
13658
13659
13660
13661
13662
13663 radius = mos_lines_width(data + i*xlen + position - sradius,
13664 2*sradius + 1);
13665 if (radius < 5)
13666 radius = 5;
13667
13668 sp = position - radius;
13669 ep = position + radius;
13670
13671 if (sp < 0 || ep > xlen) {
13672 cpl_free(buffer);
13673 return 0;
13674 }
13675
13676
13677
13678
13679
13680
13681 maxpos = sp;
13682 min = max = data[sp + i * xlen];
13683 for (j = sp; j < ep; j++) {
13684 if (data[j + i * xlen] > max) {
13685 max = data[j + i * xlen];
13686 maxpos = j;
13687 }
13688 if (data[j + i * xlen] < min) {
13689 min = data[j + i * xlen];
13690 }
13691 }
13692
13693 if (fabs(min) < 0.0000001)
13694 continue;
13695
13696 if (max - min < threshold)
13697 continue;
13698
13699 if (max > saturation)
13700 continue;
13701
13702
13703
13704
13705
13706
13707
13708
13709 halfmax = (max + min)/ 2.0;
13710
13711 fwhm = 0.0;
13712 ifwhm = 0;
13713 for (j = maxpos; j < maxpos + radius; j++) {
13714 if (j < xlen) {
13715 if (data[j + i * xlen] < halfmax) {
13716 fwhm = ifwhm + (data[j - 1 + i * xlen] - halfmax)
13717 / (data[j - 1 + i * xlen] - data[j + i * xlen]);
13718 break;
13719 }
13720 ifwhm++;
13721 }
13722 }
13723
13724 ifwhm = 0;
13725 for (j = maxpos; j > maxpos - radius; j--) {
13726 if (j >= 0) {
13727 if (data[j + i * xlen] < halfmax) {
13728 fwhm += ifwhm + (data[j + 1 + i * xlen] - halfmax)
13729 / (data[j + 1 + i * xlen] - data[j + i * xlen]);
13730 break;
13731 }
13732 ifwhm++;
13733 }
13734 }
13735
13736 if (fwhm > 3.0) {
13737 buffer[n] = fwhm - 2.0;
13738 n++;
13739 }
13740
13741 }
13742
13743 if (n == 0) {
13744 cpl_free(buffer);
13745 return 0;
13746 }
13747
13748 vector = cpl_vector_wrap(n, buffer);
13749 value = cpl_vector_get_median_const(vector);
13750 cpl_vector_unwrap(vector);
13751
13752 rms = 0.0;
13753 for (i = 0, m = 0; i < n; i++) {
13754 if (fabs(buffer[i] - value) < cut) {
13755 rms += fabs(buffer[i] - value);
13756 m++;
13757 }
13758 }
13759
13760 cpl_free(buffer);
13761
13762 if (m < 3)
13763 return 0;
13764
13765 rms /= m;
13766 rms *= 1.25;
13767
13768 value *= dispersion;
13769 rms *= dispersion;
13770
13771 *mfwhm = value;
13772 *rmsfwhm = rms;
13773
13774 *resolution = lambda / value;
13775 *rmsres = *resolution * rms / value;
13776
13777 *nlines = m;
13778
13779 return 1;
13780 }
13781
13782
13804 cpl_table *mos_resolution_table(cpl_image *image, double startwave,
13805 double dispersion, int saturation,
13806 cpl_vector *lines)
13807 {
13808
13809 cpl_table *table;
13810 double *line;
13811 double fwhm;
13812 double rmsfwhm;
13813 double resolution;
13814 double rmsres;
13815 int nref;
13816 int nlines;
13817 int i;
13818
13819
13820 nref = cpl_vector_get_size(lines);
13821 line = cpl_vector_get_data(lines);
13822
13823 table = cpl_table_new(nref);
13824 cpl_table_new_column(table, "wavelength", CPL_TYPE_DOUBLE);
13825 cpl_table_set_column_unit(table, "wavelength", "Angstrom");
13826 cpl_table_new_column(table, "fwhm", CPL_TYPE_DOUBLE);
13827 cpl_table_set_column_unit(table, "fwhm", "Angstrom");
13828 cpl_table_new_column(table, "fwhm_rms", CPL_TYPE_DOUBLE);
13829 cpl_table_set_column_unit(table, "fwhm_rms", "Angstrom");
13830 cpl_table_new_column(table, "resolution", CPL_TYPE_DOUBLE);
13831 cpl_table_new_column(table, "resolution_rms", CPL_TYPE_DOUBLE);
13832 cpl_table_new_column(table, "nlines", CPL_TYPE_INT);
13833
13834 for (i = 0; i < nref; i++) {
13835 if (mos_spectral_resolution(image, line[i], startwave, dispersion,
13836 saturation, &fwhm, &rmsfwhm,
13837 &resolution, &rmsres, &nlines)) {
13838 cpl_table_set_double(table, "wavelength", i, line[i]);
13839 cpl_table_set_double(table, "fwhm", i, fwhm);
13840 cpl_table_set_double(table, "fwhm_rms", i, rmsfwhm);
13841 cpl_table_set_double(table, "resolution", i, resolution);
13842 cpl_table_set_double(table, "resolution_rms", i, rmsres);
13843 cpl_table_set_int(table, "nlines", i, nlines);
13844 }
13845 else
13846 cpl_table_set_int(table, "nlines", i, 0);
13847 }
13848
13849 if (cpl_table_has_valid(table, "wavelength"))
13850 return table;
13851
13852 cpl_table_delete(table);
13853
13854 return NULL;
13855
13856 }
13857
13858
13876 double mos_integrate_signal(cpl_image *image, cpl_image *wavemap,
13877 int ystart, int yend, double wstart, double wend)
13878 {
13879 const char *func = "mos_integrate_signal";
13880
13881 double sum;
13882 float *sdata;
13883 float *wdata;
13884 int nx, ny;
13885 int x, y;
13886
13887
13888 if (image == NULL || wavemap == NULL) {
13889 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13890 return 0.0;
13891 }
13892
13893 if (ystart > yend || wstart >= wend) {
13894 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13895 return 0.0;
13896 }
13897
13898 nx = cpl_image_get_size_x(image);
13899 ny = cpl_image_get_size_y(image);
13900
13901 if (!(nx == cpl_image_get_size_x(wavemap)
13902 && ny == cpl_image_get_size_y(wavemap))) {
13903 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
13904 return 0.0;
13905 }
13906
13907 if (ystart < 0 || yend > ny) {
13908 cpl_error_set(func, CPL_ERROR_ACCESS_OUT_OF_RANGE);
13909 return 0.0;
13910 }
13911
13912 sdata = cpl_image_get_data(image);
13913 wdata = cpl_image_get_data(wavemap);
13914
13915 sdata += ystart*nx;
13916 wdata += ystart*nx;
13917
13918 sum = 0.0;
13919 for (y = ystart; y < yend; y++) {
13920 for (x = 0; x < nx; x++) {
13921 if (wdata[x] < wstart || wdata[x] > wend)
13922 continue;
13923 sum += sdata[x];
13924 }
13925 sdata += nx;
13926 wdata += nx;
13927 }
13928
13929 return sum;
13930
13931 }
13932
13933
13934
13935
13936
13937
13938
13939
13940
13941
13964 cpl_table *mos_load_slits_fors_mxu(cpl_propertylist *header)
13965 {
13966 const char *func = "mos_load_slits_fors_mxu";
13967
13968 cpl_table *slits;
13969 char keyname[MAX_COLNAME];
13970 const char *instrume;
13971 const char *target_name;
13972 float slit_x;
13973 float slit_y;
13974 float length;
13975
13976 double arc2mm = 0.528;
13977 int nslits;
13978 int slit_id;
13979 int fors;
13980 int chip;
13981 int found;
13982
13983
13984
13985
13986
13987
13988
13989 float low_limit1 = 10.0;
13990 float hig_limit2 = 30.0;
13991
13992
13993 if (cpl_error_get_code() != CPL_ERROR_NONE) {
13994 return NULL;
13995 }
13996
13997 if (header == NULL) {
13998 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13999 return NULL;
14000 }
14001
14002
14003
14004
14005
14006
14007 instrume = cpl_propertylist_get_string(header, "INSTRUME");
14008
14009 fors = 0;
14010 if (instrume[4] == '1')
14011 fors = 1;
14012 if (instrume[4] == '2')
14013 fors = 2;
14014
14015 if (fors != 2) {
14016 cpl_msg_error(func, "Wrong instrument: %s\n"
14017 "FORS2 is expected for MXU data", instrume);
14018 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14019 return NULL;
14020 }
14021
14022
14023
14024
14025
14026
14027
14028
14029 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
14030
14031 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14032 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
14033 "in FITS header");
14034 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14035 return NULL;
14036 }
14037
14038 if (chip != 1 && chip != 2) {
14039 cpl_msg_error(func, "Unexpected chip position in keyword "
14040 "ESO DET CHIP1 Y: %d", chip);
14041 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14042 return NULL;
14043 }
14044
14045
14046
14047
14048
14049
14050
14051 nslits = 0;
14052 slit_id = 0;
14053 found = 1;
14054
14055 while (found) {
14056 slit_id++;
14057 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d YPOS", slit_id + 100);
14058 if (cpl_propertylist_has(header, keyname)) {
14059 slit_y = cpl_propertylist_get_double(header, keyname);
14060
14061 if (chip == 1)
14062 if (slit_y < low_limit1)
14063 continue;
14064 if (chip == 2)
14065 if (slit_y > hig_limit2)
14066 continue;
14067
14068 snprintf(keyname, MAX_COLNAME, "ESO INS TARG%d NAME",
14069 slit_id + 100);
14070 if (cpl_propertylist_has(header, keyname)) {
14071 target_name = cpl_propertylist_get_string(header, keyname);
14072 if (strncmp(target_name, "refslit", 7))
14073 nslits++;
14074 }
14075 else
14076 nslits++;
14077 }
14078 else
14079 found = 0;
14080 }
14081
14082 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14083 cpl_msg_error(func, "%s while loading slits coordinates from "
14084 "FITS header", cpl_error_get_message());
14085 cpl_error_set_where(func);
14086 return NULL;
14087 }
14088
14089 if (nslits == 0) {
14090 cpl_msg_error(func, "No slits coordinates found in header");
14091 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14092 return NULL;
14093 }
14094
14095 slits = cpl_table_new(nslits);
14096 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
14097 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
14098 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
14099 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
14100 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
14101 cpl_table_set_column_unit(slits, "xtop", "pixel");
14102 cpl_table_set_column_unit(slits, "ytop", "pixel");
14103 cpl_table_set_column_unit(slits, "xbottom", "pixel");
14104 cpl_table_set_column_unit(slits, "ybottom", "pixel");
14105
14106 nslits = 0;
14107 slit_id = 0;
14108 found = 1;
14109 while (found) {
14110 slit_id++;
14111 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d YPOS", slit_id + 100);
14112 if (cpl_propertylist_has(header, keyname)) {
14113 slit_y = cpl_propertylist_get_double(header, keyname);
14114
14115 if (chip == 1)
14116 if (slit_y < low_limit1)
14117 continue;
14118 if (chip == 2)
14119 if (slit_y > hig_limit2)
14120 continue;
14121
14122
14123
14124
14125
14126
14127 slit_y = -slit_y;
14128
14129 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d XPOS", slit_id + 100);
14130 slit_x = cpl_propertylist_get_double(header, keyname);
14131 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14132 cpl_table_delete(slits);
14133 cpl_msg_error(func, "Missing keyword %s in FITS header",
14134 keyname);
14135 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14136 return NULL;
14137 }
14138
14139 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d LEN", slit_id + 100);
14140 length = cpl_propertylist_get_double(header, keyname);
14141 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14142 cpl_table_delete(slits);
14143 cpl_msg_error(func, "Missing keyword %s in FITS header",
14144 keyname);
14145 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14146 return NULL;
14147 }
14148
14149 length *= arc2mm;
14150
14151 snprintf(keyname, MAX_COLNAME, "ESO INS TARG%d NAME",
14152 slit_id + 100);
14153 if (cpl_propertylist_has(header, keyname)) {
14154 target_name = cpl_propertylist_get_string(header, keyname);
14155 if (strncmp(target_name, "refslit", 7)) {
14156 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
14157 cpl_table_set(slits, "xtop", nslits, slit_x);
14158 cpl_table_set(slits, "ytop", nslits, slit_y + length/2);
14159 cpl_table_set(slits, "xbottom", nslits, slit_x);
14160 cpl_table_set(slits, "ybottom", nslits, slit_y - length/2);
14161 nslits++;
14162 }
14163 }
14164 else {
14165 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
14166 cpl_table_set(slits, "xtop", nslits, slit_x);
14167 cpl_table_set(slits, "ytop", nslits, slit_y + length/2);
14168 cpl_table_set(slits, "xbottom", nslits, slit_x);
14169 cpl_table_set(slits, "ybottom", nslits, slit_y - length/2);
14170 nslits++;
14171 }
14172 }
14173 else
14174 found = 0;
14175 }
14176
14177 return slits;
14178 }
14179
14180
14203 cpl_table *mos_load_slits_fors_mos(cpl_propertylist *header)
14204 {
14205 const char *func = "mos_load_slits_fors_mos";
14206
14207 cpl_table *slits;
14208 char keyname[MAX_COLNAME];
14209 const char *instrume;
14210 const char *chipname;
14211 float slit_x;
14212 int first_slit, last_slit;
14213 int nslits;
14214 int slit_id;
14215 int fors;
14216 int chip;
14217 int fors_is_old;
14218
14219
14220
14221
14222
14223 float ytop[19] = { 113.9, 101.3, 89.9, 77.3, 65.9, 53.3,
14224 41.9, 29.3, 17.9, 5.3, -6.1, -18.7,
14225 -30.1, -42.7, -54.1, -66.7, -78.1, -90.7,
14226 -102.1 };
14227 float ybottom[19] = { 102.1, 90.7, 78.1, 66.7, 54.1, 42.7,
14228 30.1, 18.7, 6.1, -5.3, -17.9, -29.3,
14229 -41.9, -53.3, -65.9, -77.3, -89.9, -101.3,
14230 -113.9 };
14231
14232
14233 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14234 return NULL;
14235 }
14236
14237 if (header == NULL) {
14238 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14239 return NULL;
14240 }
14241
14242
14243
14244
14245
14246
14247 instrume = cpl_propertylist_get_string(header, "INSTRUME");
14248
14249 fors = 0;
14250 if (instrume[4] == '1')
14251 fors = 1;
14252 if (instrume[4] == '2')
14253 fors = 2;
14254
14255 if (fors == 0) {
14256 cpl_msg_error(func, "Wrong instrument found in FITS header: %s",
14257 instrume);
14258 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14259 return NULL;
14260 }
14261
14262
14263
14264
14265
14266
14267
14268 chipname = cpl_propertylist_get_string(header, "ESO DET CHIP1 ID");
14269
14270 if (chipname[0] == 'M' || chipname[0] == 'N')
14271 fors_is_old = 0;
14272 else
14273 fors_is_old = 1;
14274
14275 if (fors == 1 && fors_is_old) {
14276 first_slit = 1;
14277 last_slit = 19;
14278 }
14279 else {
14280
14281
14282
14283
14284
14285
14286
14287 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
14288
14289 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14290 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
14291 "in FITS header");
14292 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14293 return NULL;
14294 }
14295
14296 if (chip != 1 && chip != 2) {
14297 cpl_msg_error(func, "Unexpected chip position in keyword "
14298 "ESO DET CHIP1 Y: %d", chip);
14299 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14300 return NULL;
14301 }
14302
14303 if (chip == 1) {
14304 first_slit = 12;
14305 last_slit = 19;
14306 }
14307 else {
14308 first_slit = 1;
14309 last_slit = 11;
14310 }
14311 }
14312
14313
14314
14315
14316
14317
14318
14319
14320 nslits = 0;
14321 slit_id = 0;
14322 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
14323 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d POS", slit_id);
14324 if (cpl_propertylist_has(header, keyname)) {
14325 slit_x = cpl_propertylist_get_double(header, keyname);
14326 if (fabs(slit_x) < 115.0)
14327 nslits++;
14328 }
14329 else {
14330 cpl_msg_error(func, "Missing keyword %s in FITS header", keyname);
14331 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14332 return NULL;
14333 }
14334 }
14335
14336 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14337 cpl_msg_error(func, "%s while loading slits coordinates from "
14338 "FITS header", cpl_error_get_message());
14339 cpl_error_set_where(func);
14340 return NULL;
14341 }
14342
14343 if (nslits == 0) {
14344 cpl_msg_error(func, "No slits coordinates found in header");
14345 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14346 return NULL;
14347 }
14348
14349 slits = cpl_table_new(nslits);
14350 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
14351 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
14352 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
14353 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
14354 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
14355 cpl_table_set_column_unit(slits, "xtop", "pixel");
14356 cpl_table_set_column_unit(slits, "ytop", "pixel");
14357 cpl_table_set_column_unit(slits, "xbottom", "pixel");
14358 cpl_table_set_column_unit(slits, "ybottom", "pixel");
14359
14360 nslits = 0;
14361 slit_id = 0;
14362 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
14363 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d POS", slit_id);
14364 slit_x = cpl_propertylist_get_double(header, keyname);
14365 if (fabs(slit_x) < 115.0) {
14366 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
14367 cpl_table_set(slits, "xtop", nslits, slit_x);
14368 cpl_table_set(slits, "ytop", nslits, ytop[slit_id-1]);
14369 cpl_table_set(slits, "xbottom", nslits, slit_x);
14370 cpl_table_set(slits, "ybottom", nslits, ybottom[slit_id-1]);
14371 nslits++;
14372 }
14373 }
14374
14375 return slits;
14376 }
14377
14378
14402 cpl_table *mos_load_slits_fors_lss(cpl_propertylist *header)
14403 {
14404 const char *func = "mos_load_slits_fors_lss";
14405
14406 cpl_table *slits;
14407 char *slit_name;
14408 const char *instrume;
14409 int fors;
14410 int chip;
14411 float ytop;
14412 float ybottom;
14413
14414 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14415 return NULL;
14416 }
14417
14418 if (header == NULL) {
14419 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14420 return NULL;
14421 }
14422
14423
14424
14425
14426
14427
14428 instrume = cpl_propertylist_get_string(header, "INSTRUME");
14429
14430 fors = 0;
14431 if (instrume[4] == '1')
14432 fors = 1;
14433 if (instrume[4] == '2')
14434 fors = 2;
14435
14436 if (fors == 0) {
14437 cpl_msg_error(func, "Wrong instrument found in FITS header: %s",
14438 instrume);
14439 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14440 return NULL;
14441 }
14442
14443 if (fors == 1) {
14444 ytop = 109.94;
14445 ybottom = -109.94;
14446 }
14447 else {
14448
14449
14450
14451
14452
14453
14454
14455 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
14456
14457 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14458 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
14459 "in FITS header");
14460 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14461 return NULL;
14462 }
14463
14464 if (chip != 1 && chip != 2) {
14465 cpl_msg_error(func, "Unexpected chip position in keyword "
14466 "ESO DET CHIP1 Y: %d", chip);
14467 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14468 return NULL;
14469 }
14470
14471 if (chip == 1) {
14472 ytop = 30.0;
14473 ybottom = -109.94;
14474 }
14475 else {
14476 ytop = 109.94;
14477 ybottom = -20.0;
14478 }
14479 }
14480
14481
14482 slits = cpl_table_new(1);
14483 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
14484 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
14485 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
14486 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
14487 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
14488 cpl_table_set_column_unit(slits, "xtop", "pixel");
14489 cpl_table_set_column_unit(slits, "ytop", "pixel");
14490 cpl_table_set_column_unit(slits, "xbottom", "pixel");
14491 cpl_table_set_column_unit(slits, "ybottom", "pixel");
14492
14493 slit_name = (char *)cpl_propertylist_get_string(header,
14494 "ESO INS SLIT NAME");
14495
14496 cpl_table_set(slits, "ytop", 0, ytop);
14497 cpl_table_set(slits, "ybottom", 0, ybottom);
14498
14499 if (!strncmp(slit_name, "lSlit0_3arcsec", 14)) {
14500 cpl_table_set_int(slits, "slit_id", 0, 1);
14501 cpl_table_set(slits, "xbottom", 0, -0.075);
14502 cpl_table_set(slits, "xtop", 0, 0.075);
14503 }
14504 else if (!strncmp(slit_name, "lSlit0_4arcsec", 14)) {
14505 cpl_table_set_int(slits, "slit_id", 0, 2);
14506 cpl_table_set(slits, "xbottom", 0, 5.895);
14507 cpl_table_set(slits, "xtop", 0, 6.105);
14508 }
14509 else if (!strncmp(slit_name, "lSlit0_5arcsec", 14)) {
14510 cpl_table_set_int(slits, "slit_id", 0, 3);
14511 cpl_table_set(slits, "xbottom", 0, -6.135);
14512 cpl_table_set(slits, "xtop", 0, -5.865);
14513 }
14514 else if (!strncmp(slit_name, "lSlit0_7arcsec", 14)) {
14515 cpl_table_set_int(slits, "slit_id", 0, 4);
14516 cpl_table_set(slits, "xbottom", 0, 11.815);
14517 cpl_table_set(slits, "xtop", 0, 12.185);
14518 }
14519 else if (!strncmp(slit_name, "lSlit1_0arcsec", 14)) {
14520 cpl_table_set_int(slits, "slit_id", 0, 5);
14521 cpl_table_set(slits, "xbottom", 0, -12.265);
14522 cpl_table_set(slits, "xtop", 0, -11.735);
14523 }
14524 else if (!strncmp(slit_name, "lSlit1_3arcsec", 14)) {
14525 cpl_table_set_int(slits, "slit_id", 0, 6);
14526 cpl_table_set(slits, "xbottom", 0, 17.655);
14527 cpl_table_set(slits, "xtop", 0, 18.345);
14528 }
14529 else if (!strncmp(slit_name, "lSlit1_6arcsec", 14)) {
14530 cpl_table_set_int(slits, "slit_id", 0, 7);
14531 cpl_table_set(slits, "xbottom", 0, -18.425);
14532 cpl_table_set(slits, "xtop", 0, -17.575);
14533 }
14534 else if (!strncmp(slit_name, "lSlit2_0arcsec", 14)) {
14535 cpl_table_set_int(slits, "slit_id", 0, 8);
14536 cpl_table_set(slits, "xbottom", 0, 23.475);
14537 cpl_table_set(slits, "xtop", 0, 24.525);
14538 }
14539 else if (!strncmp(slit_name, "lSlit2_5arcsec", 14)) {
14540 cpl_table_set_int(slits, "slit_id", 0, 9);
14541 cpl_table_set(slits, "xbottom", 0, -24.66);
14542 cpl_table_set(slits, "xtop", 0, -23.34);
14543 }
14544 else {
14545 cpl_msg_error(func, "Invalid slit %s in keyword ESO INS SLIT NAME",
14546 slit_name);
14547 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14548 cpl_table_delete(slits);
14549 return NULL;
14550 }
14551
14552 return slits;
14553 }
14554
14555
14570 double mos_get_gain_vimos(cpl_propertylist *header)
14571 {
14572 const char *func = "mos_get_gain_vimos";
14573
14574 double gain = -1.0;
14575
14576
14577 if (cpl_error_get_code() != CPL_ERROR_NONE)
14578 return gain;
14579
14580 if (header == NULL) {
14581 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14582 return gain;
14583 }
14584
14585 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
14586 if (cpl_error_get_code()) {
14587 cpl_error_set_where(func);
14588 gain = -1.0;
14589 }
14590
14591 return gain;
14592
14593 }
14594
14595
14615 cpl_table *mos_load_slits_vimos(cpl_propertylist *header)
14616 {
14617 const char *func = "mos_load_slits_vimos";
14618
14619 cpl_table *slits;
14620 char keyname[MAX_COLNAME];
14621 float slit_x;
14622 float slit_y;
14623 float dim_x;
14624 int nslits;
14625 int slit_id;
14626 int i;
14627
14628
14629 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14630 return NULL;
14631 }
14632
14633 if (header == NULL) {
14634 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14635 return NULL;
14636 }
14637
14638 nslits = cpl_propertylist_get_int(header, "ESO INS SLIT NO");
14639
14640 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14641 cpl_error_set_where(func);
14642 return NULL;
14643 }
14644
14645 slits = cpl_table_new(nslits);
14646 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
14647 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
14648 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
14649 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
14650 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
14651 cpl_table_set_column_unit(slits, "xtop", "pixel");
14652 cpl_table_set_column_unit(slits, "ytop", "pixel");
14653 cpl_table_set_column_unit(slits, "xbottom", "pixel");
14654 cpl_table_set_column_unit(slits, "ybottom", "pixel");
14655
14656 for (i = 0; i < nslits; i++) {
14657 sprintf(keyname, "ESO INS SLIT%d ID", i+1);
14658 slit_id = cpl_propertylist_get_int(header, keyname);
14659 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14660 cpl_error_set_where(func);
14661 return NULL;
14662 }
14663 sprintf(keyname, "ESO INS SLIT%d X", i+1);
14664 slit_x = cpl_propertylist_get_double(header, keyname);
14665 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14666 cpl_error_set_where(func);
14667 return NULL;
14668 }
14669 sprintf(keyname, "ESO INS SLIT%d Y", i+1);
14670 slit_y = cpl_propertylist_get_double(header, keyname);
14671 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14672 cpl_error_set_where(func);
14673 return NULL;
14674 }
14675 sprintf(keyname, "ESO INS SLIT%d DIMX", i+1);
14676 dim_x = cpl_propertylist_get_double(header, keyname) / 2;
14677 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14678 cpl_error_set_where(func);
14679 return NULL;
14680 }
14681 cpl_table_set_int(slits, "slit_id", i, slit_id);
14682 cpl_table_set(slits, "xtop", i, slit_x - dim_x);
14683 cpl_table_set(slits, "ytop", i, slit_y);
14684 cpl_table_set(slits, "xbottom", i, slit_x + dim_x);
14685 cpl_table_set(slits, "ybottom", i, slit_y);
14686 }
14687
14688 return slits;
14689 }
14690
14691
14718 cpl_table *mos_load_overscans_vimos(const cpl_propertylist *header,
14719 int check_consistency)
14720 {
14721 const char *func = "mos_load_overscans_vimos";
14722
14723 int nx = 0;
14724 int ny = 0;
14725 int px = 0;
14726 int py = 0;
14727 int ox = 0;
14728 int oy = 0;
14729 int vx = 0;
14730 int vy = 0;
14731 int nrows;
14732 cpl_table *overscans;
14733
14734
14735 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14736 cpl_msg_error(func, "Reset your error: %s", cpl_error_get_message());
14737 return NULL;
14738 }
14739
14740 if (header == NULL) {
14741 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14742 return NULL;
14743 }
14744
14745 if (cpl_propertylist_has(header, "NAXIS1"))
14746 nx = cpl_propertylist_get_int(header, "NAXIS1");
14747 if (cpl_propertylist_has(header, "NAXIS2"))
14748 ny = cpl_propertylist_get_int(header, "NAXIS2");
14749 if (cpl_propertylist_has(header, "ESO DET OUT1 PRSCX"))
14750 px = cpl_propertylist_get_int(header, "ESO DET OUT1 PRSCX");
14751 if (cpl_propertylist_has(header, "ESO DET OUT1 PRSCY"))
14752 py = cpl_propertylist_get_int(header, "ESO DET OUT1 PRSCY");
14753 if (cpl_propertylist_has(header, "ESO DET OUT1 OVSCX"))
14754 ox = cpl_propertylist_get_int(header, "ESO DET OUT1 OVSCX");
14755 if (cpl_propertylist_has(header, "ESO DET OUT1 OVSCY"))
14756 oy = cpl_propertylist_get_int(header, "ESO DET OUT1 OVSCY");
14757 if (cpl_propertylist_has(header, "ESO DET OUT1 NX"))
14758 vx = cpl_propertylist_get_int(header, "ESO DET OUT1 NX");
14759 if (cpl_propertylist_has(header, "ESO DET OUT1 NY"))
14760 vy = cpl_propertylist_get_int(header, "ESO DET OUT1 NY");
14761
14762 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14763 cpl_msg_error(func, "Missing overscan keywords in header");
14764 cpl_error_set_where(func);
14765 return NULL;
14766 }
14767
14768 if (px < 0 || py < 0 || ox < 0 || oy < 0) {
14769 cpl_msg_error(func, "Missing overscan keywords in header");
14770 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14771 return NULL;
14772 }
14773
14774 if ((px + vx + ox != nx) || (py + vy + oy != ny)) {
14775 if (check_consistency) {
14776 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14777 return NULL;
14778 }
14779 else {
14780 cpl_msg_debug(func, "Overscans description conflicts with "
14781 "reported image sizes, "
14782 "%d + %d + %d != %d or "
14783 "%d + %d + %d != %d",
14784 px, vx, ox, nx,
14785 py, vy, oy, ny);
14786 }
14787 }
14788
14789 nrows = 0;
14790 if (px > 0)
14791 nrows++;
14792 if (ox > 0)
14793 nrows++;
14794 if (py > 0)
14795 nrows++;
14796 if (oy > 0)
14797 nrows++;
14798
14799 if (nrows > 2) {
14800 cpl_msg_error(func, "Unexpected overscan regions "
14801 "(both in X and Y direction)");
14802 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14803 return NULL;
14804 }
14805
14806
14807
14808
14809
14810
14811
14812 nrows++;
14813
14814 overscans = cpl_table_new(nrows);
14815 cpl_table_new_column(overscans, "xlow", CPL_TYPE_INT);
14816 cpl_table_new_column(overscans, "ylow", CPL_TYPE_INT);
14817 cpl_table_new_column(overscans, "xhig", CPL_TYPE_INT);
14818 cpl_table_new_column(overscans, "yhig", CPL_TYPE_INT);
14819
14820 nrows = 0;
14821
14822 cpl_table_set_int(overscans, "xlow", nrows, px);
14823 cpl_table_set_int(overscans, "ylow", nrows, py);
14824 cpl_table_set_int(overscans, "xhig", nrows, nx - ox);
14825 cpl_table_set_int(overscans, "yhig", nrows, ny - oy);
14826 nrows++;
14827
14828 if (px > 0) {
14829 cpl_table_set_int(overscans, "xlow", nrows, 0);
14830 cpl_table_set_int(overscans, "ylow", nrows, 0);
14831 cpl_table_set_int(overscans, "xhig", nrows, px);
14832 cpl_table_set_int(overscans, "yhig", nrows, ny);
14833 nrows++;
14834 }
14835
14836 if (ox > 0) {
14837 cpl_table_set_int(overscans, "xlow", nrows, nx - ox);
14838 cpl_table_set_int(overscans, "ylow", nrows, 0);
14839 cpl_table_set_int(overscans, "xhig", nrows, nx);
14840 cpl_table_set_int(overscans, "yhig", nrows, ny);
14841 nrows++;
14842 }
14843
14844 if (py > 0) {
14845 cpl_table_set_int(overscans, "xlow", nrows, 0);
14846 cpl_table_set_int(overscans, "ylow", nrows, 0);
14847 cpl_table_set_int(overscans, "xhig", nrows, nx);
14848 cpl_table_set_int(overscans, "yhig", nrows, py);
14849 nrows++;
14850 }
14851
14852 if (oy > 0) {
14853 cpl_table_set_int(overscans, "xlow", nrows, 0);
14854 cpl_table_set_int(overscans, "ylow", nrows, ny - oy);
14855 cpl_table_set_int(overscans, "xhig", nrows, nx);
14856 cpl_table_set_int(overscans, "yhig", nrows, ny);
14857 nrows++;
14858 }
14859
14860 return overscans;
14861
14862 }
14863
14864
14865 cpl_table *mos_load_overscans_fors(const cpl_propertylist *header)
14866 {
14867 const char *func = "mos_load_overscans_fors";
14868
14869 int nports;
14870 int nx = 0;
14871 int ny = 0;
14872 int px = 0;
14873 int py = 0;
14874 int ox = 0;
14875 int oy = 0;
14876 int rebin;
14877 int nrows;
14878 cpl_table *overscans;
14879
14880
14881 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14882 cpl_msg_error(func, "Reset your error: %s", cpl_error_get_message());
14883 return NULL;
14884 }
14885
14886 if (header == NULL) {
14887 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14888 return NULL;
14889 }
14890
14891 if (cpl_propertylist_has(header, "ESO DET OUTPUTS"))
14892 nports = cpl_propertylist_get_int(header, "ESO DET OUTPUTS");
14893
14894 if (nports == 4 &&
14895 cpl_propertylist_has(header, "ESO DET OUT1 PRSCX") &&
14896 cpl_propertylist_has(header, "ESO DET WIN1 BINX")) {
14897
14898 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
14899
14900 overscans = cpl_table_new(3);
14901 cpl_table_new_column(overscans, "xlow", CPL_TYPE_INT);
14902 cpl_table_new_column(overscans, "ylow", CPL_TYPE_INT);
14903 cpl_table_new_column(overscans, "xhig", CPL_TYPE_INT);
14904 cpl_table_new_column(overscans, "yhig", CPL_TYPE_INT);
14905
14906 px = 16 / rebin;
14907 ox = 16 / rebin;
14908 nx = 2080 / rebin;
14909 ny = 2048 / rebin;
14910 nrows = 0;
14911
14912 cpl_table_set_int(overscans, "xlow", nrows, px);
14913 cpl_table_set_int(overscans, "ylow", nrows, py);
14914 cpl_table_set_int(overscans, "xhig", nrows, nx - ox);
14915 cpl_table_set_int(overscans, "yhig", nrows, ny - oy);
14916 nrows++;
14917
14918 cpl_table_set_int(overscans, "xlow", nrows, 0);
14919 cpl_table_set_int(overscans, "ylow", nrows, 0);
14920 cpl_table_set_int(overscans, "xhig", nrows, px);
14921 cpl_table_set_int(overscans, "yhig", nrows, ny);
14922 nrows++;
14923
14924 cpl_table_set_int(overscans, "xlow", nrows, nx - ox);
14925 cpl_table_set_int(overscans, "ylow", nrows, 0);
14926 cpl_table_set_int(overscans, "xhig", nrows, nx);
14927 cpl_table_set_int(overscans, "yhig", nrows, ny);
14928 nrows++;
14929 }
14930 else {
14931 overscans = mos_load_overscans_vimos(header, 0);
14932 }
14933
14934 return overscans;
14935
14936 }
14937
14969 #define READY 1
14970 #ifdef READY
14971
14972 cpl_polynomial *mos_montecarlo_polyfit(cpl_table *points, cpl_table *evaluate,
14973 int samples, int order)
14974 {
14975
14976 const char *func = "mos_montecarlo_polyfit";
14977
14978 cpl_polynomial *p;
14979 cpl_polynomial *q;
14980 cpl_vector *listx;
14981 cpl_vector *listy;
14982 double err;
14983 double *x;
14984 double *px;
14985 double *x_eval;
14986 double *px_eval;
14987 double *sigma;
14988 double *vy;
14989 double *dy;
14990 int npoints, nevaluate;
14991 int i, j;
14992
14993
14994 if (points == NULL || evaluate == NULL) {
14995 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14996 return NULL;
14997 }
14998
14999 if (!cpl_table_has_column(points, "x")) {
15000 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15001 return NULL;
15002 }
15003
15004 if (cpl_table_get_column_type(points, "x") != CPL_TYPE_DOUBLE) {
15005 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15006 return NULL;
15007 }
15008
15009 if (cpl_table_has_invalid(points, "x")) {
15010 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15011 return NULL;
15012 }
15013
15014 if (!cpl_table_has_column(points, "y")) {
15015 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15016 return NULL;
15017 }
15018
15019 if (cpl_table_get_column_type(points, "y") != CPL_TYPE_DOUBLE) {
15020 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15021 return NULL;
15022 }
15023
15024 if (cpl_table_has_invalid(points, "y")) {
15025 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15026 return NULL;
15027 }
15028
15029 if (cpl_table_has_column(points, "y_err")) {
15030
15031 if (cpl_table_get_column_type(points, "y_err") != CPL_TYPE_DOUBLE) {
15032 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15033 return NULL;
15034 }
15035
15036 if (cpl_table_has_invalid(points, "y_err")) {
15037 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15038 return NULL;
15039 }
15040 }
15041
15042 if (!cpl_table_has_column(evaluate, "x")) {
15043 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15044 return NULL;
15045 }
15046
15047 if (cpl_table_get_column_type(evaluate, "x") != CPL_TYPE_DOUBLE) {
15048 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15049 return NULL;
15050 }
15051
15052 if (cpl_table_has_invalid(evaluate, "x")) {
15053 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15054 return NULL;
15055 }
15056
15057 if (samples < 2 || order < 0) {
15058 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15059 return NULL;
15060 }
15061
15062 npoints = cpl_table_get_nrow(points);
15063 listx = cpl_vector_wrap(npoints, cpl_table_get_data_double(points, "x"));
15064 listy = cpl_vector_wrap(npoints, cpl_table_get_data_double(points, "y"));
15065
15066 p = cpl_polynomial_fit_1d_create(listx, listy, order, &err);
15067
15068 if (!cpl_table_has_column(points, "y_err")) {
15069 err = sqrt(err);
15070 cpl_table_new_column(points, "y_err", CPL_TYPE_DOUBLE);
15071 cpl_table_fill_column_window_double(points, "y_err", 0, npoints, err);
15072 cpl_msg_info(func, "Error column not found - set to %f\n", err);
15073 }
15074
15075
15076
15077
15078
15079 if (cpl_table_has_column(points, "px"))
15080 cpl_table_erase_column(points, "px");
15081 cpl_table_new_column(points, "px", CPL_TYPE_DOUBLE);
15082 cpl_table_fill_column_window_double(points, "px", 0, npoints, 0);
15083 x = cpl_table_get_data_double(points, "x");
15084 px = cpl_table_get_data_double(points, "px");
15085 for (i = 0; i < npoints; i++)
15086 px[i] = cpl_polynomial_eval_1d(p, x[i], NULL);
15087
15088 nevaluate = cpl_table_get_nrow(evaluate);
15089
15090 if (cpl_table_has_column(evaluate, "px"))
15091 cpl_table_erase_column(evaluate, "px");
15092 cpl_table_new_column(evaluate, "px", CPL_TYPE_DOUBLE);
15093 cpl_table_fill_column_window_double(evaluate, "px", 0, nevaluate, 0);
15094 x_eval = cpl_table_get_data_double(evaluate, "x");
15095 px_eval = cpl_table_get_data_double(evaluate, "px");
15096 for (i = 0; i < nevaluate; i++)
15097 px_eval[i] = cpl_polynomial_eval_1d(p, x_eval[i], NULL);
15098
15099
15100
15101
15102
15103 if (cpl_table_has_column(evaluate, "sigma"))
15104 cpl_table_erase_column(evaluate, "sigma");
15105 cpl_table_new_column(evaluate, "sigma", CPL_TYPE_DOUBLE);
15106 cpl_table_fill_column_window_double(evaluate, "sigma", 0, nevaluate, 0);
15107 sigma = cpl_table_get_data_double(evaluate, "sigma");
15108
15109
15110
15111
15112
15113 if (cpl_table_has_column(points, "vy"))
15114 cpl_table_erase_column(points, "vy");
15115 cpl_table_new_column(points, "vy", CPL_TYPE_DOUBLE);
15116 cpl_table_fill_column_window_double(points, "vy", 0, npoints, 0);
15117 vy = cpl_table_get_data_double(points, "vy");
15118 dy = cpl_table_get_data_double(points, "y_err");
15119 cpl_vector_unwrap(listy);
15120 listy = cpl_vector_wrap(npoints, vy);
15121
15122 for (i = 0; i < samples; i++) {
15123 for (j = 0; j < npoints; j++)
15124 vy[j] = px[j] + dy[j] * mos_randg(1);
15125 q = cpl_polynomial_fit_1d_create(listx, listy, order, NULL);
15126 for (j = 0; j < nevaluate; j++)
15127 sigma[j] += fabs(px_eval[j]
15128 - cpl_polynomial_eval_1d(q, x_eval[j], NULL));
15129 cpl_polynomial_delete(q);
15130 }
15131
15132
15133
15134
15135
15136 cpl_table_multiply_scalar(evaluate, "sigma", 1.25);
15137 cpl_table_divide_scalar(evaluate, "sigma", samples);
15138
15139 cpl_vector_unwrap(listx);
15140 cpl_vector_unwrap(listy);
15141
15142 return p;
15143 }
15144
15145 #endif
15146
15156 cpl_error_code mos_refmask_find_gaps(cpl_mask * refmask,
15157 cpl_image * master_flat)
15158 {
15159 int nx = cpl_mask_get_size_x(refmask);
15160 int ny = cpl_mask_get_size_y(refmask);
15161
15162 int * xpos = cpl_calloc(sizeof(int), ny);
15163
15164 cpl_vector * v = cpl_vector_new(ny);
15165 cpl_vector * truev;
15166 int nvalid = 0;
15167 double * flats = cpl_vector_get_data(v);
15168
15169 double median, stdev;
15170
15171 int i;
15172
15173
15174 for (i = 1; i <= ny; i++) {
15175 int j = 0;
15176
15177 do j++;
15178 while (!cpl_mask_get(refmask, j, i) && j < nx);
15179
15180 if (j < nx) {
15181 int rejected;
15182
15183 xpos[i - 1] = j;
15184 flats[nvalid] = cpl_image_get(master_flat, j, i, &rejected);
15185 nvalid++;
15186 }
15187 else {
15188 xpos[i - 1] = -1;
15189 }
15190 }
15191
15192 truev = cpl_vector_wrap(nvalid, flats);
15193
15194 median = cpl_vector_get_median(truev);
15195 stdev = cpl_vector_get_stdev(truev);
15196
15197 cpl_vector_unwrap(truev);
15198 cpl_vector_delete(v);
15199
15200 for (i = 1; i <= ny; i++) {
15201 if (xpos[i - 1] > 0) {
15202 int rejected;
15203 double kappa = 1.0;
15204 double delta =
15205 cpl_image_get(master_flat, xpos[i - 1], i, &rejected) - median;
15206
15207 if (fabs(delta) > stdev * kappa) {
15208 int j = 0;
15209
15210 while (cpl_mask_get(refmask, xpos[i - 1] + j, i)) {
15211 cpl_mask_set(refmask, xpos[i - 1] + j, i, CPL_BINARY_0);
15212 j++;
15213 }
15214 }
15215 }
15216 }
15217
15218 cpl_free(xpos);
15219
15220 return cpl_error_get_code();
15221 }
15222
15230 cpl_error_code mos_saturation_process(cpl_image * image)
15231 {
15232 int nx = cpl_image_get_size_x(image);
15233 int ny = cpl_image_get_size_y(image);
15234 int npix = nx * ny;
15235 float * sdata = cpl_image_get_data_float(image);
15236
15237 int count, i, j, k;
15238
15239
15240
15241
15242
15243
15244
15245 for (i = 0; i < npix - nx; i++)
15246 if (sdata[i] == 0.0 && sdata[i + nx] == 0.0)
15247 sdata[i] = 65535.0;
15248
15249 for (i = npix - nx; i < npix; i++)
15250 if (sdata[i] == 0.0)
15251 sdata[i] = 65535.0;
15252
15253
15254
15255
15256
15257
15258
15259 for (i = 0; i < npix; i++) {
15260 if (sdata[i] >= 65535.0) {
15261 count = 0;
15262 for (j = i; j < npix; j++) {
15263 if (sdata[j] < 65535.0) {
15264 break;
15265 }
15266 else {
15267 count++;
15268 }
15269 }
15270 if (count < 30 && count > 2) {
15271 for (j = i; j < i + count/2; j++)
15272 sdata[j] = sdata[i] + 1000.0 * (j - i);
15273 if (count % 2 != 0) {
15274 sdata[j] = sdata[j-1] + 1000.0;
15275 j++;
15276 }
15277 for (k = j; k <= i + count; k++)
15278 sdata[k] = sdata[i] - 1000.0 * (k - i - count);
15279 i = k;
15280 }
15281 }
15282 }
15283
15284 return cpl_error_get_code();
15285 }
15286
15294 cpl_error_code mos_subtract_background(cpl_image * image)
15295 {
15296
15297
15298
15299
15300 cpl_image * bimage = mos_arc_background(image, 15, 15);
15301 cpl_image_subtract(image, bimage);
15302 cpl_image_delete(bimage);
15303
15304 return cpl_error_get_code();
15305 }
15306
15321 cpl_error_code mos_object_intersect(cpl_table ** slitss,
15322 cpl_table * origslits, int nscience)
15323 {
15324 int i, j;
15325
15326 cpl_table *summary;
15327 int summary_nobjs = 0;
15328
15329 int nobjs;
15330
15331 int nmatches;
15332 int nslits = cpl_table_get_nrow(slitss[0]);
15333
15334 const float tolerance = 5.0;
15335
15336 int maxobjs;
15337 int k, m;
15338 int nstokes, sstokes;
15339
15340 cpl_table **work;
15341
15342 work = (cpl_table **)cpl_malloc(sizeof(cpl_table *) * nscience);
15343
15344
15345
15346
15347
15348
15349
15350
15351
15352
15353 for (j = 0; j < nscience; j++) {
15354 int c_nobjs = mos_get_nobjects(slitss[j]);
15355 if (!c_nobjs)
15356 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
15357 summary_nobjs += c_nobjs;
15358 }
15359
15360 summary = cpl_table_new(summary_nobjs);
15361
15362 cpl_table_new_column(summary, "offset", CPL_TYPE_DOUBLE);
15363 cpl_table_new_column(summary, "pair", CPL_TYPE_INT);
15364
15365
15366
15367
15368
15369 nobjs = 0;
15370
15371
15372 for (j = 0; j < nscience; j++) {
15373 int c_maxobjs = mos_get_maxobjs_per_slit(slitss[j]);
15374
15375
15376 for (k = 0; k < nslits; k++) {
15377
15378
15379 for (m = 0; m < c_maxobjs; m++) {
15380 int null;
15381 char *name = cpl_sprintf("object_%d", m + 1);
15382 double obj = cpl_table_get_double(slitss[j], name, k, &null);
15383 int pos;
15384 int pair;
15385
15386 cpl_free(name);
15387
15388 if (null)
15389 break;
15390
15391
15392
15393
15394
15395
15396
15397
15398 pos = cpl_table_get_int(slitss[j], "position", k, &null);
15399 pair = cpl_table_get_int(slitss[j], "pair_id", k, &null);
15400 cpl_table_set(summary, "offset", nobjs, obj - pos);
15401 cpl_table_set(summary, "pair", nobjs, pair);
15402
15403 nobjs++;
15404 }
15405 }
15406 }
15407
15408
15409
15410
15411
15412
15413
15414
15415
15416
15417 nmatches = 0;
15418 maxobjs = mos_get_maxobjs_per_slit(slitss[0]);
15419
15420
15421
15422
15423
15424
15425
15426
15427
15428
15429
15430
15431 for (k = 0; k < nslits; k+=2) {
15432 int slitmatches = 0;
15433 for (m = 0; m < maxobjs; m++) {
15434 int null;
15435 char *name = cpl_sprintf("object_%d", m + 1);
15436 double obj = cpl_table_get_double(slitss[0], name, k, &null);
15437 double pos;
15438 int pair;
15439
15440 char *name_obj;
15441 char *name_start;
15442 char *name_end;
15443 char *name_row;
15444 char *name_row_s;
15445
15446 char *name_start_o;
15447 char *name_end_o;
15448 char *name_row_o;
15449
15450 int start, end;
15451 int length;
15452
15453 int selected;
15454
15455
15456 cpl_free(name);
15457
15458 if (null)
15459 break;
15460
15461
15462
15463
15464
15465
15466
15467
15468 pos = cpl_table_get_int(slitss[0], "position", k, &null);
15469 pair = cpl_table_get_int(slitss[0], "pair_id", k, &null);
15470
15471
15472
15473
15474
15475
15476
15477
15478
15479 cpl_table_select_all(summary);
15480
15481 cpl_table_and_selected_int(summary, "pair", CPL_EQUAL_TO, pair);
15482 cpl_table_and_selected_double(summary, "offset", CPL_LESS_THAN,
15483 obj - pos + tolerance);
15484 selected =
15485 cpl_table_and_selected_double(summary, "offset", CPL_GREATER_THAN,
15486 obj - pos - tolerance);
15487
15488
15489
15490
15491
15492
15493
15494
15495 if (selected != nscience * 2)
15496 continue;
15497
15498
15499
15500
15501
15502
15503
15504 slitmatches++;
15505
15506
15507
15508
15509
15510
15511
15512
15513
15514
15515
15516 name_obj = cpl_sprintf("object_%d", slitmatches);
15517 name_start = cpl_sprintf("start_%d", slitmatches);
15518 name_end = cpl_sprintf("end_%d", slitmatches);
15519 name_row = cpl_sprintf("row_%d", slitmatches);
15520 name_row_s = cpl_sprintf("row_stokes_%d", slitmatches);
15521
15522
15523
15524
15525
15526
15527 name_start_o = cpl_sprintf("start_%d", m + 1);
15528 name_end_o = cpl_sprintf("end_%d", m + 1);
15529 name_row_o = cpl_sprintf("row_%d", m + 1);
15530
15531
15532
15533
15534
15535 if (!cpl_table_has_column(origslits, name_obj)) {
15536 cpl_table_new_column(origslits, name_obj, CPL_TYPE_DOUBLE);
15537 cpl_table_new_column(origslits, name_start, CPL_TYPE_INT);
15538 cpl_table_new_column(origslits, name_end, CPL_TYPE_INT);
15539 cpl_table_new_column(origslits, name_row, CPL_TYPE_INT);
15540 cpl_table_new_column(origslits, name_row_s, CPL_TYPE_INT);
15541 }
15542
15543
15544
15545
15546
15547
15548
15549
15550 length = cpl_table_get_int(origslits, "length", k + 1, &null);
15551
15552
15553
15554
15555
15556
15557 start = cpl_table_get_int(slitss[0], name_start_o, k, &null);
15558 end = cpl_table_get_int(slitss[0], name_end_o, k, &null);
15559
15560
15561
15562
15563
15564
15565
15566
15567
15568
15569 cpl_table_set_double(origslits, name_obj, k, obj);
15570 cpl_table_set_double(origslits, name_obj, k + 1, obj - length);
15571
15572 cpl_table_set_int(origslits, name_start, k, start);
15573 cpl_table_set_int(origslits, name_start, k + 1, start - length);
15574
15575 cpl_table_set_int(origslits, name_end, k, end);
15576 cpl_table_set_int(origslits, name_end, k + 1, end - length);
15577
15578
15579
15580
15581
15582
15583
15584
15585
15586
15587
15588
15589
15590 cpl_table_set_int(origslits, name_row, k, nmatches);
15591 nmatches++;
15592 cpl_table_set_int(origslits, name_row, k + 1, nmatches);
15593 nmatches++;
15594
15595 cpl_free(name_obj);
15596 cpl_free(name_start);
15597 cpl_free(name_end);
15598 cpl_free(name_row);
15599 cpl_free(name_row_s);
15600
15601 cpl_free(name_start_o);
15602 cpl_free(name_end_o);
15603 cpl_free(name_row_o);
15604 }
15605 }
15606
15607
15608
15609
15610
15611
15612 cpl_table_delete(summary);
15613
15614 if (!nmatches)
15615 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
15616
15617
15618
15619
15620
15621
15622
15623
15624
15625
15626
15627 maxobjs = mos_get_maxobjs_per_slit(origslits);
15628 nstokes = nmatches / 2;
15629
15630 for (k = 0; k < nslits; k++) {
15631 if (k % 2) {
15632 nstokes = sstokes;
15633 }
15634 else {
15635 sstokes = nstokes;
15636 }
15637
15638 for (m = 0; m < maxobjs; m++) {
15639 char *name = cpl_sprintf("row_%d", m + 1);
15640 char *namestokes = cpl_sprintf("row_stokes_%d", m + 1);
15641
15642 if (!cpl_table_is_valid(origslits, name, k)) {
15643 cpl_free(name);
15644 cpl_free(namestokes);
15645 break;
15646 }
15647 else {
15648 nmatches--;
15649 nstokes--;
15650 cpl_table_set_int(origslits, name, k, nmatches);
15651 cpl_table_set_int(origslits, namestokes, k, nstokes);
15652 }
15653
15654 cpl_free(name);
15655 cpl_free(namestokes);
15656 }
15657 }
15658
15659
15660
15661
15662
15663
15664
15665
15666
15667 for (j = 0; j < maxobjs; j++) {
15668 char *name = cpl_sprintf("object_%d", j + 1);
15669 cpl_table_fill_invalid_double(origslits, name, -1);
15670 cpl_free(name);
15671
15672 name = cpl_sprintf("start_%d", j + 1);
15673 cpl_table_fill_invalid_int(origslits, name, -1);
15674 cpl_free(name);
15675
15676 name = cpl_sprintf("end_%d", j + 1);
15677 cpl_table_fill_invalid_int(origslits, name, -1);
15678 cpl_free(name);
15679
15680 name = cpl_sprintf("row_%d", j + 1);
15681 cpl_table_fill_invalid_int(origslits, name, -1);
15682 cpl_free(name);
15683
15684 name = cpl_sprintf("row_stokes_%d", j + 1);
15685 cpl_table_fill_invalid_int(origslits, name, -1);
15686 cpl_free(name);
15687 }
15688
15689
15690
15691
15692
15693
15694
15695
15696
15697
15698
15699
15700 for (i = 0; i < nscience; i++) {
15701 int c_maxobjs = mos_get_maxobjs_per_slit(slitss[i]);
15702
15703 work[i] = cpl_table_duplicate(slitss[i]);
15704
15705 for (m = 0; m < c_maxobjs; m++) {
15706 char *object_o = cpl_sprintf("object_%d", m + 1);
15707 char *start_o = cpl_sprintf("start_%d", m + 1);
15708 char *end_o = cpl_sprintf("end_%d", m + 1);
15709 char *row_o = cpl_sprintf("row_%d", m + 1);
15710
15711 cpl_table_erase_column(slitss[i], object_o);
15712 cpl_table_erase_column(slitss[i], start_o);
15713 cpl_table_erase_column(slitss[i], end_o);
15714 cpl_table_erase_column(slitss[i], row_o);
15715 }
15716 }
15717
15718
15719
15720
15721
15722 for (k = 0; k < nslits; k++) {
15723 for (j = 0; j < maxobjs; j++) {
15724 double object_w, object_r;
15725 int start_w, start_r;
15726 int end_w, end_r;
15727 int row_w, row_r;
15728
15729 char *object_i = cpl_sprintf("object_%d", j + 1);
15730 char *start_i = cpl_sprintf("start_%d", j + 1);
15731 char *end_i = cpl_sprintf("end_%d", j + 1);
15732 char *row_i = cpl_sprintf("row_%d", j + 1);
15733
15734
15735 if (!cpl_table_is_valid(origslits, object_i, k))
15736 break;
15737
15738
15739
15740
15741
15742
15743
15744
15745
15746
15747
15748 object_w = cpl_table_get_double(origslits, object_i, k, NULL);
15749 start_w = cpl_table_get_int (origslits, start_i, k, NULL);
15750 end_w = cpl_table_get_int (origslits, end_i, k, NULL);
15751 row_w = cpl_table_get_int (origslits, row_i, k, NULL);
15752
15753 for (i = 0; i < nscience; i++) {
15754 int c_maxobjs = mos_get_maxobjs_per_slit(work[i]);
15755 int minpos;
15756 double mindiff, diff;
15757 char *object_o;
15758 char *start_o;
15759 char *end_o;
15760 char *row_o;
15761
15762 for (m = 0; m < c_maxobjs; m++) {
15763 object_o = cpl_sprintf("object_%d", m + 1);
15764 start_o = cpl_sprintf("start_%d", m + 1);
15765 end_o = cpl_sprintf("end_%d", m + 1);
15766 row_o = cpl_sprintf("row_%d", m + 1);
15767
15768 if (!cpl_table_is_valid(work[i], object_o, k))
15769 break;
15770
15771 object_r = cpl_table_get_double(work[i], object_o, k, NULL);
15772 start_r = cpl_table_get_int (work[i], start_o, k, NULL);
15773 end_r = cpl_table_get_int (work[i], end_o, k, NULL);
15774 row_r = cpl_table_get_int (work[i], row_o, k, NULL);
15775
15776 diff = fabs(object_w - object_r);
15777 if (m) {
15778 if (mindiff > diff) {
15779 mindiff = diff;
15780 minpos = m;
15781 }
15782 }
15783 else {
15784 mindiff = diff;
15785 minpos = 0;
15786 }
15787
15788 cpl_free(object_o);
15789 cpl_free(start_o);
15790 cpl_free(end_o);
15791 cpl_free(row_o);
15792 }
15793
15794 object_o = cpl_sprintf("object_%d", minpos + 1);
15795 start_o = cpl_sprintf("start_%d", minpos + 1);
15796 end_o = cpl_sprintf("end_%d", minpos + 1);
15797 row_o = cpl_sprintf("row_%d", minpos + 1);
15798
15799 if (!cpl_table_has_column(slitss[i], object_i)) {
15800 cpl_table_new_column(slitss[i], object_i, CPL_TYPE_DOUBLE);
15801 cpl_table_new_column(slitss[i], start_i, CPL_TYPE_INT);
15802 cpl_table_new_column(slitss[i], end_i, CPL_TYPE_INT);
15803 cpl_table_new_column(slitss[i], row_i, CPL_TYPE_INT);
15804 cpl_table_fill_invalid_double(slitss[i], object_i, -1);
15805 cpl_table_fill_invalid_int (slitss[i], start_i, -1);
15806 cpl_table_fill_invalid_int (slitss[i], end_i, -1);
15807 cpl_table_fill_invalid_int (slitss[i], row_i, -1);
15808 }
15809
15810 cpl_table_set_double(slitss[i], object_i, k,
15811 cpl_table_get_double(work[i], object_o,
15812 k, NULL));
15813 cpl_table_set_int(slitss[i], start_i , k,
15814 cpl_table_get_int(work[i], start_o, k, NULL));
15815 cpl_table_set_int(slitss[i], end_i , k,
15816 cpl_table_get_int(work[i], end_o, k, NULL));
15817 cpl_table_set_int(slitss[i], row_i , k, row_w);
15818
15819 cpl_free(object_o);
15820 cpl_free(start_o);
15821 cpl_free(end_o);
15822 cpl_free(row_o);
15823 }
15824
15825 cpl_free(object_i);
15826 cpl_free(start_i);
15827 cpl_free(end_i);
15828 cpl_free(row_i);
15829 }
15830 }
15831
15832 for (i = 0; i < nscience; i++)
15833 cpl_table_delete(work[i]);
15834
15835 cpl_free(work);
15836
15837
15838 return cpl_error_get_code();
15839 }
15840
15841
15849 int mos_get_maxobjs_per_slit(cpl_table * slits)
15850 {
15851 int maxobjs = 1;
15852
15853 char * colname = cpl_sprintf("object_%d", maxobjs);
15854
15855 while (cpl_table_has_column(slits, colname)) {
15856 maxobjs++;
15857 cpl_free(colname);
15858 colname = cpl_sprintf("object_%d", maxobjs);
15859 }
15860
15861 cpl_free(colname);
15862
15863 maxobjs--;
15864
15865 return maxobjs;
15866 }
15867
15875 int mos_get_nobjects(cpl_table * slits)
15876 {
15877 int nobjs = 0;
15878
15879 int nslits = cpl_table_get_nrow(slits);
15880 int maxobjs = mos_get_maxobjs_per_slit(slits);
15881
15882 int k, m;
15883
15884 for (k = 0; k < nslits; k++) {
15885 for (m = 0; m < maxobjs; m++) {
15886 char * name = cpl_sprintf("object_%d", m + 1);
15887 int null = !cpl_table_is_valid(slits, name, k);
15888
15889 cpl_free(name);
15890
15891 if (null) break;
15892 else nobjs++;
15893 }
15894 }
15895
15896 return nobjs;
15897 }
15898
15906 int mos_check_slits(cpl_table * slits)
15907 {
15908
15909 cpl_propertylist * sort;
15910
15911 int nslits = cpl_table_get_nrow(slits);
15912
15913 int k, null;
15914
15915
15916 for (k = 0; k < nslits; k++) {
15917 double ytop = cpl_table_get_double(slits, "ytop", k, &null);
15918 double ybottom = cpl_table_get_double(slits, "ybottom", k, &null);
15919
15920 double xtop = cpl_table_get_double(slits, "xtop", k, &null);
15921 double xbottom = cpl_table_get_double(slits, "xbottom", k, &null);
15922
15923 int nmiss = (int)((ytop - ybottom) / 90.0 + 0.5);
15924
15925 if (nmiss > 1) {
15926 cpl_msg_warning(cpl_func,
15927 "Some slits could not be properly detected. "
15928 "There might be accountable inaccuracies.");
15929 while (nmiss > 1) {
15930 cpl_table_set_size(slits, nslits + 1);
15931
15932
15933
15934
15935 cpl_table_set_double(slits, "xtop", nslits, xtop);
15936 cpl_table_set_double(slits, "xbottom", nslits, xbottom);
15937
15938
15939 if (k == 0) {
15940 cpl_table_set_double(slits, "ybottom", nslits, ybottom);
15941 cpl_table_set_double(slits, "ytop", nslits, ybottom
15942 + 85.0);
15943 ybottom += 90.0;
15944 cpl_table_set_double(slits, "ybottom", k, ybottom);
15945 } else {
15946 cpl_table_set_double(slits, "ytop", nslits, ytop);
15947 cpl_table_set_double(slits, "ybottom", nslits, ytop
15948 - 85.0);
15949 ytop -= 90.0;
15950 cpl_table_set_double(slits, "ytop", k, ytop);
15951 }
15952
15953 nslits++; nmiss--;
15954 }
15955 }
15956 }
15957
15958 sort = cpl_propertylist_new();
15959 cpl_propertylist_append_bool(sort, "ytop", 1);
15960 cpl_table_sort(slits, sort);
15961 cpl_propertylist_delete(sort);
15962
15963 return 0;
15964 }
15965
15988 cpl_table *mos_load_slits_fors_pmos(cpl_propertylist *header)
15989 {
15990 int m, null;
15991 int halfsize;
15992
15993 cpl_propertylist * sort;
15994 cpl_table * slits;
15995
15996 slits = mos_load_slits_fors_mos(header);
15997 halfsize = cpl_table_get_nrow(slits);
15998
15999 cpl_table_set_size(slits, 2 * halfsize);
16000
16001 for (m = 0; m < halfsize; m++) {
16002
16003 double gap = 1.4;
16004
16005 double length =
16006 cpl_table_get(slits, "ytop", m, &null) -
16007 cpl_table_get(slits, "ybottom", m, &null);
16008
16009 if (m) {
16010 double interval =
16011 cpl_table_get(slits, "ybottom", m - 1, &null) -
16012 cpl_table_get(slits, "ytop", m, &null);
16013
16014 gap = (interval - length) / 2;
16015 }
16016
16017 cpl_table_set(slits, "slit_id", m + halfsize,
16018 cpl_table_get(slits, "slit_id", m, &null) - 1);
16019
16020 cpl_table_set(slits, "xtop", m + halfsize,
16021 cpl_table_get(slits, "xtop", m, &null));
16022
16023 cpl_table_set(slits, "xbottom", m + halfsize,
16024 cpl_table_get(slits, "xbottom", m, &null));
16025
16026 cpl_table_set(slits, "ytop", m + halfsize,
16027 cpl_table_get(slits, "ytop", m, &null) + gap + length);
16028
16029 cpl_table_set(slits, "ybottom", m + halfsize,
16030 cpl_table_get(slits, "ytop", m, &null) + gap);
16031 }
16032
16033 for (m = 0; m < 2 * halfsize; m++) {
16034 cpl_table_set(slits, "ytop", m,
16035 cpl_table_get(slits, "ytop", m, &null) - 5.3);
16036
16037 cpl_table_set(slits, "ybottom", m,
16038 cpl_table_get(slits, "ybottom", m, &null) - 5.3);
16039
16040 }
16041
16042 sort = cpl_propertylist_new();
16043 cpl_propertylist_append_bool(sort, "ytop", 1);
16044 cpl_table_sort(slits, sort);
16045
16046 cpl_propertylist_delete(sort);
16047
16048 return slits;
16049 }
16050
16051 int * fors_get_nobjs_perslit(cpl_table * slits)
16052 {
16053 int nslits = cpl_table_get_nrow(slits);
16054 int maxobjs = mos_get_maxobjs_per_slit(slits);
16055
16056 int * nobjs_per_slit = cpl_malloc(sizeof(int) * nslits);
16057
16058 int k, m;
16059
16060 for (k = 0; k < nslits; k++) {
16061 int nobjs = 0;
16062 for (m = 0; m < maxobjs; m++) {
16063 char * name = cpl_sprintf("object_%d", m + 1);
16064 int null = !cpl_table_is_valid(slits, name, k);
16065
16066 cpl_free(name);
16067
16068 if (null) break;
16069 else nobjs++;
16070 }
16071
16072 nobjs_per_slit[k] = nobjs;
16073 }
16074
16075 return nobjs_per_slit;
16076 }