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 <fors_utils.h>
00040 #include <moses.h>
00041
00042
00043
00044
00045
00046
00047 float cpl_tools_get_median_float(float *, int);
00048
00049 #define MAX_COLNAME (80)
00050 #define STRETCH_FACTOR (1.20)
00051
00052
00053
00054 static int mos_multiplex = -1;
00055 static int mos_region_size = 800;
00056
00057 static double default_lines_hi[] = {
00058 5577.338,
00059 5889.953,
00060 5895.923,
00061 5915.301,
00062 5932.862,
00063 5953.420,
00064 6257.961,
00065 6287.434,
00066 6300.304,
00067 6306.869,
00068 6363.780,
00069 6498.729,
00070 6533.044,
00071 6553.617,
00072 6841.945,
00073 6863.955,
00074 6870.994,
00075 6889.288,
00076 6900.833,
00077 6912.623,
00078 6923.220,
00079 6939.521,
00080 6969.930,
00081 7003.858,
00082 7244.907,
00083 7276.405,
00084 7284.439,
00085 7316.282,
00086 7329.148,
00087 7340.885,
00088 7358.659,
00089 7571.746,
00090 7750.640,
00091 7759.996,
00092 7794.112,
00093 7808.467,
00094 7821.503,
00095 7841.266,
00096 7913.708,
00097 7949.204,
00098 7964.650,
00099 7993.332,
00100 8014.059,
00101 8310.719,
00102 8344.602,
00103 8382.392,
00104 8399.170,
00105 8415.231,
00106 8430.174,
00107 8452.250,
00108 8493.389,
00109 8791.186,
00110 8827.096,
00111 8885.850,
00112 8903.114,
00113 8943.395,
00114 8988.366
00115 };
00116
00117 static double default_lines_lo[] = {
00118 5577.338,
00119 6300.304,
00120 6863.955,
00121 7571.746,
00122 7964.650,
00123 7993.332
00124 };
00125
00126
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
00190
00191
00192
00193
00194
00195
00196 static void mos_seed(void)
00197 {
00198 srand((unsigned int)time((time_t *)0));
00199 }
00200
00201 static double mos_randg(int seme)
00202 {
00203 static int doit = 1;
00204 static int gotit = 1;
00205 double x1, x2, w, y1;
00206 static double y2;
00207
00208 if (gotit && seme) {
00209 mos_seed();
00210 gotit = 0;
00211 }
00212
00213 if (doit) {
00214 doit = 0;
00215 do {
00216 x1 = 2.0 * (double)rand() / RAND_MAX - 1.0;
00217 x2 = 2.0 * (double)rand() / RAND_MAX - 1.0;
00218 w = x1 * x1 + x2 * x2;
00219 } while (w >= 1.0 || w == 0.0);
00220
00221 w = sqrt( (-2.0 * log(w)) / w);
00222
00223 y1 = x1 * w;
00224 y2 = x2 * w;
00225 return y1;
00226 }
00227
00228 doit = 1;
00229 return y2;
00230 }
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240 static cpl_image *mos_image_vertical_median_filter(cpl_image *ima_in,
00241 int filtsizey, int refrow,
00242 int above, int below, int step)
00243 {
00244
00245 const char *func = "mos_image_general_median_filter";
00246
00247 cpl_image *filt_img = NULL;
00248 int col, row;
00249 float *buf = NULL;
00250 float *data;
00251 float *fdata;
00252 int upright_y, loleft_y;
00253 int j;
00254 int yIsEven = !(filtsizey - (filtsizey/2)*2);
00255 int f2y;
00256 int nx = cpl_image_get_size_x(ima_in);
00257 int ny = cpl_image_get_size_y(ima_in);
00258 int firstRow;
00259
00260
00261 if (yIsEven) filtsizey++;
00262
00263 if (ny <= filtsizey) {
00264 cpl_msg_error(func,
00265 "Median filter size: %d, image size: %d", filtsizey, ny);
00266 return NULL;
00267 }
00268
00269 f2y = filtsizey / 2;
00270
00271 filt_img = cpl_image_duplicate(ima_in);
00272 buf = cpl_malloc(filtsizey * sizeof(float));
00273 data = cpl_image_get_data(ima_in);
00274 fdata = cpl_image_get_data(filt_img);
00275
00276 firstRow = refrow - step * (below / step);
00277 if (firstRow < f2y)
00278 firstRow += step;
00279
00280 for (col = 0; col < nx; col++) {
00281 for (row = firstRow; row < refrow + above; row += step) {
00282 if (row >= ny - f2y)
00283 break;
00284 loleft_y = row - f2y;
00285 upright_y = row + f2y + 1;
00286 for (j = loleft_y; j < upright_y; j++)
00287 buf[j - loleft_y] = data[col + j * nx];
00288
00289 fdata[col + row * nx] = cpl_tools_get_median_float(buf, filtsizey);
00290 }
00291 }
00292
00293 cpl_free(buf);
00294
00295 return filt_img;
00296
00297 }
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 static int peakPosition(const float *data, int size, float *position,
00317 int minPoints)
00318 {
00319 int i;
00320 int count = 0;
00321 float *copy;
00322 float max, median, level, pos, variance, uniformVariance;
00323 double sum, weights;
00324
00325
00326 if (data == NULL)
00327 return 1;
00328
00329 if (size < 5)
00330 return 1;
00331
00332
00333
00334
00335
00336
00337 copy = (float *) cpl_malloc(size*sizeof(float));
00338 for (i = 0; i < size; i++)
00339 copy[i] = data[i];
00340 median = cpl_tools_get_median_float(copy, size);
00341 cpl_free(copy);
00342
00343
00344
00345
00346
00347
00348 max = data[0];
00349 for (i = 1; i < size; i++)
00350 if (data[i] > max)
00351 max = data[i];
00352
00353
00354
00355
00356
00357
00358
00359 if (max-median < 0.00001)
00360 return 1;
00361
00362
00363
00364
00365
00366
00367
00368 level = (max + median) / 2;
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378 count = 0;
00379 for (i = 0, sum = 0., weights = 0.; i < size; i++) {
00380 if (data[i] > level) {
00381 count++;
00382 weights += (data[i] - median);
00383 sum += i * (data[i] - median);
00384 }
00385 }
00386
00387
00388
00389
00390
00391
00392
00393 if (count < minPoints)
00394 return 1;
00395
00396 pos = sum / weights;
00397 for (i = 0, sum = 0., weights = 0.; i < size; i++) {
00398 if (data[i] > level) {
00399 weights++;
00400 sum += (i - pos) * (i - pos);
00401 }
00402 }
00403 variance = sqrt(sum / weights);
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413 uniformVariance = sqrt(size*size/3 - pos*size + pos*pos);
00414
00415 if (variance > 0.8 * uniformVariance)
00416 return 1;
00417
00418 *position = pos + 0.5;
00419
00420 return 0;
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
00464
00465
00466
00467
00468
00469
00470 static double values_to_dx(double v1, double v2, double v3)
00471 {
00472
00473 static double epsilon = 0.00000001;
00474 double r = 2.0;
00475
00476
00477 if (v1 > v2 || v3 > v2)
00478 return r;
00479
00480 if (2 * v2 - v1 - v3 < epsilon)
00481 return r;
00482
00483 r = 0.5 * (v3 - v1) / (2 * v2 - v3 - v1);
00484
00485 return r;
00486
00487 }
00488
00489
00490
00491
00492
00493
00494
00495 static float *min_filter(float *buffer, int length, int size)
00496 {
00497 float *minf = cpl_calloc(length, sizeof(float));
00498 float min;
00499 int start = size / 2;
00500 int end = length - size / 2;
00501 int i, j;
00502
00503
00504 for (i = start; i < end; i++) {
00505 min = buffer[i-start];
00506 for (j = i - start + 1; j <= i + start; j++)
00507 if (min > buffer[j])
00508 min = buffer[j];
00509 minf[i] = min;
00510 }
00511
00512 for (i = 0; i < start; i++)
00513 minf[i] = minf[start];
00514
00515 for (i = end; i < length; i++)
00516 minf[i] = minf[end-1];
00517
00518 return minf;
00519 }
00520
00521
00522
00523
00524
00525
00526
00527 static float *max_filter(float *buffer, int length, int size)
00528 {
00529 float *maxf = cpl_calloc(length, sizeof(float));
00530 float max;
00531 int start = size / 2;
00532 int end = length - size / 2;
00533 int i, j;
00534
00535
00536 for (i = start; i < end; i++) {
00537 max = buffer[i-start];
00538 for (j = i - start + 1; j <= i + start; j++)
00539 if (max < buffer[j])
00540 max = buffer[j];
00541 maxf[i] = max;
00542 }
00543
00544 for (i = 0; i < start; i++)
00545 maxf[i] = maxf[start];
00546
00547 for (i = end; i < length; i++)
00548 maxf[i] = maxf[end-1];
00549
00550 return maxf;
00551 }
00552
00553
00554
00555
00556
00557
00558
00559 static float *smo_filter(float *buffer, int length, int size)
00560 {
00561 float *smof = cpl_calloc(length, sizeof(float));
00562 double sum;
00563 int start = size / 2;
00564 int end = length - size / 2;
00565 int i, j;
00566
00567
00568 for (i = start; i < end; i++) {
00569 sum = 0.0;
00570 for (j = i - start; j <= i + start; j++)
00571 sum += buffer[j];
00572 smof[i] = sum / size;
00573 }
00574
00575 for (i = 0; i < start; i++)
00576 smof[i] = smof[start];
00577
00578 for (i = end; i < length; i++)
00579 smof[i] = smof[end-1];
00580
00581 return smof;
00582 }
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603 static cpl_polynomial *read_global_distortion(cpl_table *global, int row)
00604 {
00605 cpl_polynomial *poly = NULL;
00606 int p[2];
00607 int degree = 2;
00608 int null;
00609 double coeff;
00610
00611 char name[MAX_COLNAME];
00612
00613
00614 for (p[0] = 0; p[0] <= degree; p[0]++) {
00615 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
00616 snprintf(name, MAX_COLNAME, "a%d%d", p[0], p[1]);
00617 coeff = cpl_table_get_double(global, name, row, &null);
00618 if (null)
00619 continue;
00620 if (poly == NULL)
00621 poly = cpl_polynomial_new(2);
00622 cpl_polynomial_set_coeff(poly, p, coeff);
00623 }
00624 }
00625
00626 return poly;
00627 }
00628
00629 static cpl_table *write_global_distortion(cpl_table *global, int row,
00630 cpl_polynomial *poly)
00631 {
00632 cpl_table *table;
00633 int p[2];
00634 int degree = 2;
00635 int nrow = 10;
00636
00637 char name[MAX_COLNAME];
00638
00639
00640 if (global) {
00641 table = global;
00642 }
00643 else {
00644 table = cpl_table_new(nrow);
00645 for (p[0] = 0; p[0] <= degree; p[0]++) {
00646 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
00647 snprintf(name, MAX_COLNAME, "a%d%d", p[0], p[1]);
00648 cpl_table_new_column(table, name, CPL_TYPE_DOUBLE);
00649 }
00650 }
00651 }
00652
00653 if (poly) {
00654 for (p[0] = 0; p[0] <= degree; p[0]++) {
00655 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
00656 snprintf(name, MAX_COLNAME, "a%d%d", p[0], p[1]);
00657 cpl_table_set_double(table, name, row,
00658 cpl_polynomial_get_coeff(poly, p));
00659 }
00660 }
00661 }
00662
00663 return table;
00664 }
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676 #define SEGNO(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
00677 static int robustLinearFit(cpl_bivector *list, double *a, double *b,
00678 double *abdev)
00679 {
00680 cpl_vector *vx;
00681 cpl_vector *vy;
00682 cpl_vector *va;
00683
00684 double aa, bb, bcomp, b1, b2, del, abdevt, f, f1, f2, sigb, temp, d, sum;
00685 double sx, sy, sxy, sxx, chisq;
00686 double *arr;
00687 double aa_ls, bb_ls;
00688 double *x;
00689 double *y;
00690 int np;
00691 int iter;
00692 int max_iterate = 30;
00693 int i;
00694
00695
00696 np = cpl_bivector_get_size(list);
00697 vx = cpl_bivector_get_x(list);
00698 vy = cpl_bivector_get_y(list);
00699 x = cpl_vector_get_data(vx);
00700 y = cpl_vector_get_data(vy);
00701
00702 sx = sy = sxx = sxy = 0.00;
00703 for (i = 0; i < np; i++) {
00704 sx += x[i];
00705 sy += y[i];
00706 sxy += x[i] * y[i];
00707 sxx += x[i] * x[i];
00708 }
00709
00710 del = np * sxx - sx * sx;
00711 aa_ls = aa = (sxx * sy - sx * sxy) / del;
00712 bb_ls = bb = (np * sxy - sx * sy) / del;
00713
00714 chisq = 0.00;
00715 for (i = 0; i < np; i++) {
00716 temp = y[i] - (aa+bb*x[i]);
00717 temp *= temp;
00718 chisq += temp;
00719 }
00720
00721 va = cpl_vector_new(np);
00722 arr = cpl_vector_get_data(va);
00723 sigb = sqrt(chisq/del);
00724 b1 = bb;
00725
00726 bcomp = b1;
00727 sum = 0.00;
00728 for (i = 0; i < np; i++) {
00729 arr[i] = y[i] - bcomp * x[i];
00730 }
00731 aa = cpl_vector_get_median_const(va);
00732 abdevt = 0.0;
00733 for (i = 0; i < np; i++) {
00734 d = y[i] - (bcomp * x[i] + aa);
00735 abdevt += fabs(d);
00736 if (y[i] != 0.0)
00737 d /= fabs(y[i]);
00738 if (fabs(d) > 1e-7)
00739 sum += (d >= 0.0 ? x[i] : -x[i]);
00740 }
00741 f1 = sum;
00742
00743 b2 = bb + SEGNO(3.0 * sigb, f1);
00744
00745 bcomp = b2;
00746 sum = 0.00;
00747 for (i = 0; i < np; i++) {
00748 arr[i] = y[i] - bcomp * x[i];
00749 }
00750 aa = cpl_vector_get_median_const(va);
00751 abdevt = 0.0;
00752 for (i = 0; i < np; i++) {
00753 d = y[i] - (bcomp * x[i] + aa);
00754 abdevt += fabs(d);
00755 if (y[i] != 0.0)
00756 d /= fabs(y[i]);
00757 if (fabs(d) > 1e-7)
00758 sum += (d >= 0.0 ? x[i] : -x[i]);
00759 }
00760 f2 = sum;
00761
00762 if (fabs(b2-b1)<1e-7) {
00763 *a = aa;
00764 *b = bb;
00765 *abdev = abdevt / (double)np;
00766 cpl_vector_delete(va);
00767 return 0;
00768 }
00769
00770 iter = 0;
00771 while (f1*f2 > 0.0) {
00772 bb = 2.0*b2-b1;
00773 b1 = b2;
00774 f1 = f2;
00775 b2 = bb;
00776
00777 bcomp = b2;
00778 sum = 0.00;
00779 for (i = 0; i < np; i++) {
00780 arr[i] = y[i] - bcomp * x[i];
00781 }
00782 aa = cpl_vector_get_median_const(va);
00783 abdevt = 0.0;
00784 for (i = 0; i < np; i++) {
00785 d = y[i] - (bcomp * x[i] + aa);
00786 abdevt += fabs(d);
00787 if (y[i] != 0.0)
00788 d /= fabs(y[i]);
00789 if (fabs(d) > 1e-7)
00790 sum += (d >= 0.0 ? x[i] : -x[i]);
00791 }
00792 f2 = sum;
00793 iter++;
00794 if (iter >= max_iterate)
00795 break;
00796 }
00797 if (iter >= max_iterate) {
00798 *a = aa_ls;
00799 *b = bb_ls;
00800 *abdev = -1.0;
00801 cpl_vector_delete(va);
00802 return 1;
00803 }
00804
00805 sigb = 0.01 * sigb;
00806 while (fabs(b2-b1) > sigb) {
00807 bb = 0.5 * (b1 + b2);
00808 if ((fabs(bb-b1) < 1e-7) || (fabs(bb-b2) < 1e-7))
00809 break;
00810 bcomp = bb;
00811 sum = 0.0;
00812 for (i = 0; i < np; i++) {
00813 arr[i] = y[i] - bcomp * x[i];
00814 }
00815 aa = cpl_vector_get_median_const(va);
00816 abdevt = 0.0;
00817 for (i = 0; i < np; i++) {
00818 d = y[i] - (bcomp * x[i] + aa);
00819 abdevt += fabs(d);
00820 if (y[i] != 0.0)
00821 d /= fabs(y[i]);
00822 if (fabs(d) > 1e-7)
00823 sum += (d >= 0.0 ? x[i] : -x[i]);
00824 }
00825 f = sum;
00826
00827 if (f*f1 >= 0.0) {
00828 f1=f;
00829 b1=bb;
00830 }
00831 else {
00832 f2=f;
00833 b2=bb;
00834 }
00835 }
00836 cpl_vector_delete(va);
00837 *a = aa;
00838 *b = bb;
00839 *abdev = abdevt / np;
00840 return 0;
00841 }
00842 #undef SEGNO
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854 cpl_table *mos_hough_table(cpl_table *table, const char *x, const char *y)
00855 {
00856 cpl_table *output;
00857 double *xdata;
00858 double *ydata;
00859 double *xodata;
00860 double *yodata;
00861 int npoints;
00862 int opoints;
00863 int i, j, k;
00864
00865
00866 npoints = cpl_table_get_nrow(table);
00867 opoints = npoints*(npoints-1)/2;
00868
00869 output = cpl_table_new(opoints);
00870 cpl_table_new_column(output, "m", CPL_TYPE_DOUBLE);
00871 cpl_table_new_column(output, "q", CPL_TYPE_DOUBLE);
00872 cpl_table_fill_column_window_double(output, "m", 0, opoints, 0.0);
00873 cpl_table_fill_column_window_double(output, "q", 0, opoints, 0.0);
00874
00875 xodata = cpl_table_get_data_double(output, "m");
00876 yodata = cpl_table_get_data_double(output, "q");
00877
00878 cpl_table_cast_column(table, x, "x", CPL_TYPE_DOUBLE);
00879 cpl_table_cast_column(table, y, "y", CPL_TYPE_DOUBLE);
00880
00881 xdata = cpl_table_get_data_double(table, "x");
00882 ydata = cpl_table_get_data_double(table, "y");
00883
00884 k = 0;
00885 for (i = 0; i < npoints; i++) {
00886 for (j = i+1; j < npoints; j++) {
00887 xodata[k] = (ydata[i]-ydata[j])/(xdata[i]-xdata[j]);
00888 yodata[k] = ydata[i] - xodata[k] * xdata[i];
00889 k++;
00890 }
00891 }
00892
00893 if (k != opoints)
00894 printf("Assert k = %d, expected %d\n", k, opoints);
00895
00896 cpl_table_erase_column(table, "x");
00897 cpl_table_erase_column(table, "y");
00898
00899 return output;
00900 }
00901
00902
00903
00904
00905
00906
00907
00908 static void mos_extraction(cpl_image *sciwin, cpl_image *skywin,
00909 cpl_image *extracted, cpl_image *sky,
00910 cpl_image *error, int nobjects, int extraction,
00911 double ron, double conad, int ncomb)
00912 {
00913
00914 cpl_vector *vprofile;
00915 cpl_matrix *kernel;
00916 cpl_image *smowin;
00917
00918 int i, j;
00919 int specLen;
00920 int numRows;
00921 int index;
00922 int iter;
00923 int maxIter = 2;
00924 int smoothBox = 31;
00925 double nsigma = 5.0;
00926
00927 double sumWeight, sum, sumSky, sumProf, variance, weight;
00928 double *profile;
00929 double *buffer;
00930 float *edata;
00931 float *ekdata;
00932 float *endata;
00933 float *sdata;
00934 float *kdata;
00935 float *fdata;
00936
00937 double value;
00938
00939
00940 specLen = cpl_image_get_size_x(sciwin);
00941 numRows = cpl_image_get_size_y(sciwin);
00942
00943 edata = cpl_image_get_data(extracted);
00944 edata += nobjects * specLen;
00945
00946 ekdata = cpl_image_get_data(sky);
00947 ekdata += nobjects * specLen;
00948
00949 endata = cpl_image_get_data(error);
00950 endata += nobjects * specLen;
00951
00952 sdata = cpl_image_get_data(sciwin);
00953 kdata = cpl_image_get_data(skywin);
00954
00955
00956
00957
00958
00959
00960
00961 if (extraction && numRows > 5) {
00962 smowin = mos_image_filter_median(sciwin, 3, 3);
00963 fdata = cpl_image_get_data(smowin);
00964 for (i = 0; i < specLen; i++)
00965 for (j = 0, edata[i] = 0.0; j < numRows; j++)
00966 edata[i] += fdata[i + j * specLen];
00967 cpl_image_delete(smowin);
00968 }
00969 else {
00970 for (i = 0; i < specLen; i++)
00971 for (j = 0, edata[i] = 0.0; j < numRows; j++)
00972 edata[i] += sdata[i + j * specLen];
00973 }
00974
00975 if (extraction) {
00976
00977 profile = cpl_calloc(specLen * numRows, sizeof(double));
00978 buffer = cpl_calloc(specLen, sizeof(double));
00979
00980 for (iter = 0; iter < maxIter; iter++) {
00981
00982
00983
00984
00985
00986 for (i = 0; i < specLen; i++) {
00987 for (j = 0; j < numRows; j++) {
00988 index = i + j * specLen;
00989
00990 if (fabs(edata[i]) > 0.00001)
00991 profile[index] = sdata[index] / edata[i];
00992 else
00993 profile[index] = 0.0;
00994 }
00995 }
00996
00997 for (j = 0; j < numRows; j++) {
00998
00999
01000
01001
01002
01003 for (i = 0; i < specLen - smoothBox; i++) {
01004 vprofile = cpl_vector_wrap(smoothBox, profile + i + j*specLen);
01005 value = cpl_vector_get_median_const(vprofile);
01006 cpl_vector_unwrap(vprofile);
01007 if (value < 0)
01008 value = 0.0;
01009 buffer[i + smoothBox / 2] = value;
01010 }
01011
01012
01013
01014
01015
01016 vprofile = cpl_vector_wrap(smoothBox / 2, profile + j*specLen);
01017 value = cpl_vector_get_mean(vprofile);
01018 cpl_vector_unwrap(vprofile);
01019
01020 if (value < 0)
01021 value = 0.0;
01022
01023 for (i = 0; i < smoothBox / 2; i++)
01024 buffer[i] = value;
01025
01026 vprofile = cpl_vector_wrap(smoothBox / 2,
01027 profile + specLen - smoothBox/2 + j*specLen);
01028 value = cpl_vector_get_mean(vprofile);
01029 cpl_vector_unwrap(vprofile);
01030
01031 if (value < 0)
01032 value = 0.0;
01033
01034 for (i = 0; i < smoothBox / 2; i++)
01035 buffer[i + specLen - smoothBox / 2] = value;
01036
01037 for (i = 0; i < specLen; i++)
01038 profile[i + j * specLen] = buffer[i];
01039
01040 }
01041
01042
01043
01044
01045
01046 for (i = 0; i < specLen; i++) {
01047 for (j = 0, value = 0.0; j < numRows; j++)
01048 value += profile[i + j * specLen];
01049 if (value > 0.00001)
01050 for (j = 0; j < numRows; j++)
01051 profile[i + j * specLen] /= value;
01052 else
01053 for (j = 0; j < numRows; j++)
01054 profile[i + j * specLen] = 0.0;
01055 }
01056
01057
01058
01059
01060
01061
01062 for (i = 0; i < specLen; i++) {
01063 sum = 0.0;
01064 sumSky = 0.0;
01065 sumWeight = 0.0;
01066 sumProf = 0.0;
01067 for (j = 0; j < numRows; j++) {
01068 index = i + j * specLen;
01069
01070
01071
01072 variance = ron*ron + fabs(edata[i] * profile[index] + kdata[index])
01073 / conad;
01074 variance /= ncomb;
01075 value = sdata[index] - edata[i] * profile[index];
01076 if (fabs(value) / sqrt(variance) < nsigma) {
01077 weight = 1000000 * profile[index] / variance;
01078 sum += weight * sdata[index];
01079 sumSky += weight * kdata[index];
01080 sumWeight += weight * profile[index];
01081 sumProf += profile[index];
01082 }
01083
01084
01085
01086 }
01087
01088 if (sumWeight > 0.00001) {
01089 edata[i] = sum / sumWeight;
01090 ekdata[i] = sumSky / sumWeight;
01091 endata[i] = 1000 * sqrt(sumProf / sumWeight);
01092 }
01093 else {
01094
01095
01096
01097
01098
01099 endata[i] = sqrt(ron*ron + fabs(edata[i] + ekdata[i]) / conad);
01100 }
01101 }
01102 }
01103 cpl_free(profile);
01104 cpl_free(buffer);
01105 }
01106 else {
01107
01108
01109
01110
01111
01112
01113 for (i = 0; i < specLen; i++)
01114 for (j = 0, ekdata[i] = 0.0; j < numRows; j++)
01115 ekdata[i] += kdata[i + j * specLen];
01116
01117
01118
01119
01120
01121 for (i = 0; i < specLen; i++)
01122 endata[i] = sqrt(ron*ron + fabs(edata[i] + ekdata[i]) / conad);
01123
01124 }
01125
01126 }
01127
01128
01175 cpl_table *mos_global_distortion(cpl_table *slits, cpl_table *maskslits,
01176 cpl_table *ids, cpl_table *crv,
01177 double reference)
01178 {
01179 const char *func = "mos_global_distortion";
01180
01181 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01182
01183 cpl_table *global = NULL;
01184 cpl_table *coeff;
01185 cpl_table *dummy;
01186 cpl_vector *ci;
01187 cpl_vector *xmask;
01188 cpl_vector *ymask;
01189 cpl_bivector *mask;
01190 cpl_vector *xccd;
01191 cpl_vector *yccd;
01192 cpl_bivector *ccd;
01193 cpl_polynomial *poly;
01194 double *xtop;
01195 double *ytop;
01196 double *xbottom;
01197 double *ybottom;
01198 double *mxtop;
01199 double *mytop;
01200 double *mxbottom;
01201 double *mybottom;
01202 int *position;
01203 int *length;
01204 int *slit_id;
01205 int *mslit_id;
01206 int nslits, nmaskslits, npoints;
01207 int order;
01208 int i, j;
01209 int minslit = 6;
01210
01211
01212
01213
01214
01215 if (slits == NULL || maskslits == NULL || ids == NULL || crv == NULL) {
01216 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01217 return NULL;
01218 }
01219
01220
01221
01222
01223 nslits = cpl_table_get_nrow(slits);
01224
01225
01226
01227
01228 if (nslits < minslit) {
01229 cpl_msg_warning(func, "Too few slits (%d < %d) for global "
01230 "distortion model determination", nslits, minslit);
01231 return NULL;
01232 }
01233
01234
01235
01236
01237 nmaskslits = cpl_table_get_nrow(maskslits);
01238
01239 length = cpl_table_get_data_int(slits, "length");
01240 position = cpl_table_get_data_int(slits, "position");
01241 slit_id = cpl_table_get_data_int(slits, "slit_id");
01242 mslit_id = cpl_table_get_data_int(maskslits, "slit_id");
01243 xtop = cpl_table_get_data_double(slits, "xtop");
01244 ytop = cpl_table_get_data_double(slits, "ytop");
01245 xbottom = cpl_table_get_data_double(slits, "xbottom");
01246 ybottom = cpl_table_get_data_double(slits, "ybottom");
01247 mxtop = cpl_table_get_data_double(maskslits, "xtop");
01248 mytop = cpl_table_get_data_double(maskslits, "ytop");
01249 mxbottom = cpl_table_get_data_double(maskslits, "xbottom");
01250 mybottom = cpl_table_get_data_double(maskslits, "ybottom");
01251
01252
01253
01254
01255
01256
01257 coeff = cpl_table_new(nslits);
01258 cpl_table_copy_structure(coeff, ids);
01259 cpl_table_new_column(coeff, "xccd", CPL_TYPE_DOUBLE);
01260 cpl_table_new_column(coeff, "yccd", CPL_TYPE_DOUBLE);
01261 cpl_table_new_column(coeff, "xmask", CPL_TYPE_DOUBLE);
01262 cpl_table_new_column(coeff, "ymask", CPL_TYPE_DOUBLE);
01263
01264
01265
01266
01267 for (i = 0; i < nslits; i++) {
01268 for (j = 0; j < nmaskslits; j++) {
01269 if (slit_id[i] == mslit_id[j]) {
01270 cpl_table_set_double(coeff, "xmask", i,
01271 (mxtop[j] + mxbottom[j]) / 2);
01272 cpl_table_set_double(coeff, "ymask", i,
01273 (mytop[j] + mybottom[j]) / 2);
01274 }
01275 }
01276 }
01277
01278 if (cpl_table_has_invalid(coeff, "xmask")) {
01279 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
01280 cpl_table_delete(coeff);
01281 return NULL;
01282 }
01283
01284 for (i = 0; i < nslits; i++) {
01285 cpl_table_set_double(coeff, "xccd", i, (xtop[i] + xbottom[i]) / 2);
01286 cpl_table_set_double(coeff, "yccd", i, (ytop[i] + ybottom[i]) / 2);
01287 }
01288
01289
01290
01291
01292 for (i = 0; i < nslits; i++) {
01293
01294 if (length[i] == 0)
01295 continue;
01296
01297 cpl_table_and_selected_window(ids, position[i], length[i]);
01298 dummy = cpl_table_extract_selected(ids);
01299 for (j = 0; j < 6; j++) {
01300 if (cpl_table_has_column(dummy, clab[j])) {
01301 if (length[i] - cpl_table_count_invalid(dummy, clab[j]) > 10) {
01302 cpl_table_set_double(coeff, clab[j], i,
01303 cpl_table_get_column_median(dummy, clab[j]));
01304 }
01305 }
01306 }
01307
01308 cpl_table_delete(dummy);
01309 cpl_table_select_all(ids);
01310
01311 }
01312
01313
01314
01315
01316 for (j = 0; j < 6; j++) {
01317 if (cpl_table_has_column(coeff, clab[j])) {
01318 cpl_table_and_selected_invalid(coeff, clab[j]);
01319
01320 if (cpl_table_not_selected(coeff))
01321 dummy = cpl_table_extract_selected(coeff);
01322 else
01323 break;
01324
01325 npoints = cpl_table_get_nrow(dummy);
01326
01327 if (npoints >= 6) {
01328
01329 if (npoints >= 12)
01330 order = 2;
01331 else
01332 order = 1;
01333
01334 ci = cpl_vector_wrap(npoints,
01335 cpl_table_get_data_double(dummy, clab[j]));
01336 if (j) {
01337 xccd = cpl_vector_wrap(npoints,
01338 cpl_table_get_data_double(dummy, "xccd"));
01339 yccd = cpl_vector_wrap(npoints,
01340 cpl_table_get_data_double(dummy, "yccd"));
01341 ccd = cpl_bivector_wrap_vectors(xccd, yccd);
01342
01343
01344 poly = cpl_polynomial_fit_2d_create(ccd, ci, order, NULL);
01345
01346 cpl_bivector_unwrap_vectors(ccd);
01347 cpl_vector_unwrap(xccd);
01348 cpl_vector_unwrap(yccd);
01349 cpl_vector_unwrap(ci);
01350 }
01351 else {
01352 xmask = cpl_vector_wrap(npoints,
01353 cpl_table_get_data_double(dummy, "xmask"));
01354 ymask = cpl_vector_wrap(npoints,
01355 cpl_table_get_data_double(dummy, "ymask"));
01356 mask = cpl_bivector_wrap_vectors(xmask, ymask);
01357
01358
01359 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
01360
01361 cpl_bivector_unwrap_vectors(mask);
01362 cpl_vector_unwrap(xmask);
01363 cpl_vector_unwrap(ymask);
01364 cpl_vector_unwrap(ci);
01365 }
01366 }
01367 else {
01368 int p[2] = {0, 0};
01369 poly = cpl_polynomial_new(2);
01370 cpl_polynomial_set_coeff(poly, p,
01371 cpl_table_get_column_median(dummy, clab[j]));
01372 }
01373
01374 cpl_table_delete(dummy);
01375
01376 global = write_global_distortion(global, j, poly);
01377
01378 cpl_polynomial_delete(poly);
01379
01380 cpl_table_select_all(coeff);
01381 }
01382 }
01383
01384
01385
01386
01387 cpl_table_delete(coeff);
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397 cpl_table_set_double(global, "a00", 6, reference);
01398
01399
01400
01401
01402
01403
01404 coeff = cpl_table_duplicate(crv);
01405 cpl_table_new_column(coeff, "xmask", CPL_TYPE_DOUBLE);
01406 cpl_table_new_column(coeff, "ymask", CPL_TYPE_DOUBLE);
01407 slit_id = cpl_table_get_data_int(coeff, "slit_id");
01408 npoints = cpl_table_get_nrow(coeff);
01409
01410
01411
01412
01413 for (i = 0; i < npoints; i++) {
01414 for (j = 0; j < nmaskslits; j++) {
01415 if (slit_id[i] == mslit_id[j]) {
01416 if (i%2) {
01417 cpl_table_set_double(coeff, "xmask", i, mxbottom[j]);
01418 cpl_table_set_double(coeff, "ymask", i, mybottom[j]);
01419 }
01420 else {
01421 cpl_table_set_double(coeff, "xmask", i, mxtop[j]);
01422 cpl_table_set_double(coeff, "ymask", i, mytop[j]);
01423 }
01424 }
01425 }
01426 }
01427
01428
01429
01430
01431 if (cpl_table_has_invalid(coeff, "xmask")) {
01432 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
01433 cpl_table_delete(coeff);
01434 return NULL;
01435 }
01436
01437
01438
01439
01440 for (j = 0; j < 3; j++) {
01441 if (cpl_table_has_column(coeff, clab[j])) {
01442 cpl_table_and_selected_invalid(coeff, clab[j]);
01443
01444 if (cpl_table_not_selected(coeff))
01445 dummy = cpl_table_extract_selected(coeff);
01446 else
01447 break;
01448
01449 npoints = cpl_table_get_nrow(dummy);
01450
01451 if (npoints >= 6) {
01452
01453 if (npoints >= 12)
01454 order = 2;
01455 else
01456 order = 1;
01457
01458 ci = cpl_vector_wrap(npoints,
01459 cpl_table_get_data_double(dummy, clab[j]));
01460 xmask = cpl_vector_wrap(npoints,
01461 cpl_table_get_data_double(dummy, "xmask"));
01462 ymask = cpl_vector_wrap(npoints,
01463 cpl_table_get_data_double(dummy, "ymask"));
01464 mask = cpl_bivector_wrap_vectors(xmask, ymask);
01465
01466 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
01467
01468 cpl_bivector_unwrap_vectors(mask);
01469 cpl_vector_unwrap(ci);
01470 cpl_vector_unwrap(xmask);
01471 cpl_vector_unwrap(ymask);
01472 }
01473 else {
01474 int p[2] = {0, 0};
01475 poly = cpl_polynomial_new(2);
01476 cpl_polynomial_set_coeff(poly, p,
01477 cpl_table_get_column_median(dummy, clab[j]));
01478 }
01479
01480 cpl_table_delete(dummy);
01481
01482 global = write_global_distortion(global, j + 7, poly);
01483
01484 cpl_polynomial_delete(poly);
01485 cpl_table_select_all(coeff);
01486 }
01487 }
01488
01489
01490
01491
01492 cpl_table_delete(coeff);
01493
01494
01495
01496
01497 return global;
01498
01499 }
01500
01501
01539 cpl_table *mos_build_slit_location(cpl_table *global, cpl_table *maskslits,
01540 int ysize)
01541 {
01542 const char *func = "mos_build_slit_location";
01543
01544 cpl_propertylist *sort_col;
01545 cpl_polynomial *ids0;
01546 cpl_polynomial *crv[3];
01547 cpl_polynomial *loc_crv;
01548 cpl_vector *point;
01549 cpl_table *slits;
01550 int nslits;
01551 int *slit_id;
01552 double *dpoint;
01553 double *xtop;
01554 double *ytop;
01555 double *xbottom;
01556 double *ybottom;
01557 double *mxtop;
01558 double *mytop;
01559 double *mxbottom;
01560 double *mybottom;
01561 int i, j;
01562
01563
01564 if (global == NULL || maskslits == NULL) {
01565 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01566 return NULL;
01567 }
01568
01569 nslits = cpl_table_get_nrow(maskslits);
01570 slit_id = cpl_table_get_data_int(maskslits, "slit_id");
01571 mxtop = cpl_table_get_data_double(maskslits, "xtop");
01572 mytop = cpl_table_get_data_double(maskslits, "ytop");
01573 mxbottom = cpl_table_get_data_double(maskslits, "xbottom");
01574 mybottom = cpl_table_get_data_double(maskslits, "ybottom");
01575
01576 slits = cpl_table_duplicate(maskslits);
01577
01578 xtop = cpl_table_get_data_double(slits, "xtop");
01579 ytop = cpl_table_get_data_double(slits, "ytop");
01580 xbottom = cpl_table_get_data_double(slits, "xbottom");
01581 ybottom = cpl_table_get_data_double(slits, "ybottom");
01582
01583 ids0 = read_global_distortion(global, 0);
01584 crv[0] = read_global_distortion(global, 7);
01585 crv[1] = read_global_distortion(global, 8);
01586 crv[2] = read_global_distortion(global, 9);
01587
01588 loc_crv = cpl_polynomial_new(1);
01589
01590 point = cpl_vector_new(2);
01591 dpoint = cpl_vector_get_data(point);
01592
01593 for (i = 0; i < nslits; i++) {
01594 dpoint[0] = mxtop[i];
01595 dpoint[1] = mytop[i];
01596
01597 xtop[i] = cpl_polynomial_eval(ids0, point);
01598
01599 for (j = 0; j < 3; j++)
01600 if (crv[j])
01601 cpl_polynomial_set_coeff(loc_crv, &j,
01602 cpl_polynomial_eval(crv[j], point));
01603
01604 ytop[i] = cpl_polynomial_eval_1d(loc_crv, xtop[i], NULL);
01605
01606 dpoint[0] = mxbottom[i];
01607 dpoint[1] = mybottom[i];
01608 xbottom[i] = cpl_polynomial_eval(ids0, point);
01609
01610 for (j = 0; j < 3; j++)
01611 if (crv[j])
01612 cpl_polynomial_set_coeff(loc_crv, &j,
01613 cpl_polynomial_eval(crv[j], point));
01614
01615 ybottom[i] = cpl_polynomial_eval_1d(loc_crv, xbottom[i], NULL);
01616 }
01617
01618 cpl_vector_delete(point);
01619 cpl_polynomial_delete(ids0);
01620 cpl_polynomial_delete(loc_crv);
01621 for (j = 0; j < 3; j++)
01622 cpl_polynomial_delete(crv[j]);
01623
01624 sort_col = cpl_propertylist_new();
01625 cpl_propertylist_append_bool(sort_col, "ytop", 1);
01626 cpl_table_sort(slits, sort_col);
01627 cpl_table_sort(maskslits, sort_col);
01628 cpl_propertylist_delete(sort_col);
01629
01630
01631
01632
01633
01634 cpl_table_and_selected_double(slits, "ybottom", CPL_GREATER_THAN, ysize-1);
01635 cpl_table_or_selected_double(slits, "ytop", CPL_LESS_THAN, 0);
01636 cpl_table_erase_selected(slits);
01637
01638 nslits = cpl_table_get_nrow(slits);
01639
01640 if (nslits == 0) {
01641 cpl_msg_warning(func, "No slits found on the CCD");
01642 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
01643 cpl_table_delete(slits);
01644 return NULL;
01645 }
01646
01647 if (nslits > 1)
01648 cpl_msg_info(func, "Slit location: %d slits are entirely or partially "
01649 "contained in CCD", nslits);
01650 else
01651 cpl_msg_info(func, "Slit location: %d slit is entirely or partially "
01652 "contained in CCD", nslits);
01653
01654 return slits;
01655
01656 }
01657
01658
01685 cpl_table *mos_build_curv_coeff(cpl_table *global, cpl_table *maskslits,
01686 cpl_table *slits)
01687 {
01688 const char *func = "mos_build_curv_coeff";
01689
01690 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01691
01692
01693 cpl_polynomial *crv[3];
01694 cpl_vector *point;
01695 cpl_table *polytraces;
01696 double *dpoint;
01697 double *xtop;
01698 double *ytop;
01699 double *xbottom;
01700 double *ybottom;
01701 int *slit_id;
01702 int *valid_id;
01703 int nslits, nvalid;
01704 int found;
01705 int i, j, k;
01706
01707
01708 if (global == NULL || slits == NULL || maskslits == NULL) {
01709 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01710 return NULL;
01711 }
01712
01713 nslits = cpl_table_get_nrow(maskslits);
01714 slit_id = cpl_table_get_data_int(maskslits, "slit_id");
01715 xtop = cpl_table_get_data_double(maskslits, "xtop");
01716 ytop = cpl_table_get_data_double(maskslits, "ytop");
01717 xbottom = cpl_table_get_data_double(maskslits, "xbottom");
01718 ybottom = cpl_table_get_data_double(maskslits, "ybottom");
01719
01720 polytraces = cpl_table_new(2*nslits);
01721 cpl_table_new_column(polytraces, "slit_id", CPL_TYPE_INT);
01722 for (i = 0; i < 3; i++)
01723 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
01724
01725 crv[0] = read_global_distortion(global, 7);
01726 crv[1] = read_global_distortion(global, 8);
01727 crv[2] = read_global_distortion(global, 9);
01728
01729 point = cpl_vector_new(2);
01730 dpoint = cpl_vector_get_data(point);
01731
01732 for (i = 0; i < nslits; i++) {
01733 for (j = 0; j < 2; j++) {
01734
01735 cpl_table_set_int(polytraces, "slit_id", 2*i+j, slit_id[i]);
01736
01737 if (j) {
01738 dpoint[0] = xbottom[i];
01739 dpoint[1] = ybottom[i];
01740 }
01741 else {
01742 dpoint[0] = xtop[i];
01743 dpoint[1] = ytop[i];
01744 }
01745
01746 for (k = 0; k < 3; k++)
01747 if (crv[j])
01748 cpl_table_set_double(polytraces, clab[k], 2*i+j,
01749 cpl_polynomial_eval(crv[k], point));
01750 }
01751 }
01752
01753 cpl_vector_delete(point);
01754 for (j = 0; j < 3; j++)
01755 cpl_polynomial_delete(crv[j]);
01756
01757
01758
01759
01760
01761 nvalid = cpl_table_get_nrow(slits);
01762 valid_id = cpl_table_get_data_int(slits, "slit_id");
01763 cpl_table_unselect_all(polytraces);
01764 for (i = 0; i < nslits; i++) {
01765 found = 0;
01766 for (j = 0; j < nvalid; j++) {
01767 if (slit_id[i] == valid_id[j]) {
01768 found = 1;
01769 break;
01770 }
01771 }
01772 if (!found) {
01773 cpl_table_select_row(polytraces, 2*i);
01774 cpl_table_select_row(polytraces, 2*i + 1);
01775 }
01776 }
01777 cpl_table_erase_selected(polytraces);
01778
01779 nslits = cpl_table_get_nrow(polytraces);
01780
01781 if (nslits == 0) {
01782 cpl_msg_warning(func, "No slits found on the CCD");
01783 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
01784 cpl_table_delete(polytraces);
01785 return NULL;
01786 }
01787
01788 if (nslits > 2)
01789 cpl_msg_info(func, "Curvature model: %d slits are entirely or "
01790 "partially contained in CCD", nslits / 2);
01791 else
01792 cpl_msg_info(func, "Curvature model: %d slit is entirely or "
01793 "partially contained in CCD", nslits / 2);
01794
01795 return polytraces;
01796 }
01797
01798
01840 cpl_table *mos_build_disp_coeff(cpl_table *global, cpl_table *slits)
01841 {
01842 const char *func = "mos_build_disp_coeff";
01843
01844 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01845
01846 cpl_polynomial *ids[6];
01847 cpl_vector *point;
01848 cpl_table *idscoeff;
01849 double *dpoint;
01850 double *xtop;
01851 double *ytop;
01852 double *xbottom;
01853 double *ybottom;
01854 int *position;
01855 int *length;
01856 int nslits;
01857 int nrows;
01858 int order;
01859 int ylow, yhig;
01860 int i, j, k;
01861
01862
01863 if (global == NULL || slits == NULL) {
01864 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01865 return NULL;
01866 }
01867
01868 nslits = cpl_table_get_nrow(slits);
01869 position = cpl_table_get_data_int(slits, "position");
01870 length = cpl_table_get_data_int(slits, "length");
01871 xtop = cpl_table_get_data_double(slits, "xtop");
01872 ytop = cpl_table_get_data_double(slits, "ytop");
01873 xbottom = cpl_table_get_data_double(slits, "xbottom");
01874 ybottom = cpl_table_get_data_double(slits, "ybottom");
01875
01876 for (i = 0; i < 6; i++)
01877 ids[i] = read_global_distortion(global, i);
01878
01879 for (i = 0; i < 6; i++)
01880 if (ids[i] == NULL)
01881 break;
01882
01883 order = i - 1;
01884
01885 if (order < 1) {
01886 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
01887 return NULL;
01888 }
01889
01890 nrows = 0;
01891 for (i = 0; i < nslits; i++)
01892 nrows += length[i];
01893
01894 idscoeff = cpl_table_new(nrows);
01895
01896 for (j = 0; j <= order; j++)
01897 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
01898
01899 cpl_table_new_column(idscoeff, "error", CPL_TYPE_DOUBLE);
01900 cpl_table_fill_column_window_double(idscoeff, "error", 0, nrows, 0.0);
01901 cpl_table_new_column(idscoeff, "nlines", CPL_TYPE_INT);
01902 cpl_table_fill_column_window_int(idscoeff, "nlines", 0, nrows, 0);
01903
01904 point = cpl_vector_new(2);
01905 dpoint = cpl_vector_get_data(point);
01906
01907 for (i = 0; i < nslits; i++) {
01908
01909 if (length[i] == 0)
01910 continue;
01911
01912 ylow = position[i];
01913 yhig = ylow + length[i];
01914
01915 for (j = 0; j <= order; j++) {
01916 if (j) {
01917 for (k = 0; k < length[i]; k++) {
01918 dpoint[0] = xbottom[i] + k*(xtop[i]-xbottom[i])/length[i];
01919 dpoint[1] = ybottom[i] + k*(ytop[i]-ybottom[i])/length[i];
01920 cpl_table_set_double(idscoeff, clab[j], ylow + k,
01921 cpl_polynomial_eval(ids[j], point));
01922 }
01923 }
01924 else {
01925 for (k = 0; k < length[i]; k++) {
01926 cpl_table_set_double(idscoeff, clab[0], ylow + k,
01927 xbottom[i] + k*(xtop[i]-xbottom[i])/length[i]);
01928 }
01929 }
01930 }
01931 }
01932
01933 cpl_vector_delete(point);
01934 for (j = 0; j < 6; j++)
01935 cpl_polynomial_delete(ids[j]);
01936
01937 return idscoeff;
01938
01939 }
01940
01941
01964 cpl_image *mos_subtract_sky(cpl_image *science, cpl_table *slits,
01965 cpl_table *polytraces, double reference,
01966 double blue, double red, double dispersion)
01967 {
01968 const char *func = "mos_subtract_sky";
01969
01970 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01971
01972
01973 cpl_image *sky;
01974 cpl_bivector *list;
01975 cpl_vector *listx;
01976 cpl_vector *listy;
01977 cpl_polynomial *polytop;
01978 cpl_polynomial *polybot;
01979 cpl_polynomial *trend;
01980
01981 int *slit_id;
01982 double *dlistx;
01983 double *dlisty;
01984 float *sdata;
01985 float *kdata;
01986 double top, bot;
01987 int itop, ibot;
01988 double coeff;
01989 double ytop, ybot;
01990 double m, q, err;
01991 int npix;
01992
01993 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
01994 int nx, ny;
01995 int nslits;
01996 int *length;
01997 int missing_top, missing_bot;
01998 int order;
01999 int null;
02000 int window = 50;
02001 int count;
02002 int i, j, k;
02003
02004
02005 if (science == NULL || slits == NULL || polytraces == NULL) {
02006 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02007 return NULL;
02008 }
02009
02010 if (dispersion <= 0.0) {
02011 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02012 return NULL;
02013 }
02014
02015 if (red - blue < dispersion) {
02016 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02017 return NULL;
02018 }
02019
02020 nx = cpl_image_get_size_x(science);
02021 ny = cpl_image_get_size_y(science);
02022
02023 sky = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
02024
02025 sdata = cpl_image_get_data(science);
02026 kdata = cpl_image_get_data(sky);
02027
02028 nslits = cpl_table_get_nrow(slits);
02029 order = cpl_table_get_ncol(polytraces) - 2;
02030 length = cpl_table_get_data_int(slits, "length");
02031 slit_id = cpl_table_get_data_int(slits, "slit_id");
02032
02033
02034
02035
02036
02037
02038 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
02039 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
02040
02041 for (i = 0; i < nslits; i++) {
02042
02043 if (length[i] == 0)
02044 continue;
02045
02046
02047
02048
02049
02050
02051
02052 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
02053
02054 start_pixel = refpixel - pixel_below;
02055 if (start_pixel < 0)
02056 start_pixel = 0;
02057
02058 end_pixel = refpixel + pixel_above;
02059 if (end_pixel > nx)
02060 end_pixel = nx;
02061
02062 missing_top = 0;
02063 polytop = cpl_polynomial_new(1);
02064 for (k = 0; k <= order; k++) {
02065 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
02066 if (null) {
02067 cpl_polynomial_delete(polytop);
02068 missing_top = 1;
02069 break;
02070 }
02071 cpl_polynomial_set_coeff(polytop, &k, coeff);
02072 }
02073
02074 missing_bot = 0;
02075 polybot = cpl_polynomial_new(1);
02076 for (k = 0; k <= order; k++) {
02077 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
02078 if (null) {
02079 cpl_polynomial_delete(polybot);
02080 missing_bot = 1;
02081 break;
02082 }
02083 cpl_polynomial_set_coeff(polybot, &k, coeff);
02084 }
02085
02086 if (missing_top && missing_bot) {
02087 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
02088 slit_id[i]);
02089 continue;
02090 }
02091
02092
02093
02094
02095
02096
02097
02098 if (missing_top) {
02099 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
02100 "the spectral curvature of the lower edge "
02101 "is used instead.", slit_id[i]);
02102 polytop = cpl_polynomial_duplicate(polybot);
02103 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02104 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02105 k = 0;
02106 coeff = cpl_polynomial_get_coeff(polybot, &k);
02107 coeff += ytop - ybot;
02108 cpl_polynomial_set_coeff(polytop, &k, coeff);
02109 }
02110
02111 if (missing_bot) {
02112 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
02113 "the spectral curvature of the upper edge "
02114 "is used instead.", slit_id[i]);
02115 polybot = cpl_polynomial_duplicate(polytop);
02116 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02117 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02118 k = 0;
02119 coeff = cpl_polynomial_get_coeff(polytop, &k);
02120 coeff -= ytop - ybot;
02121 cpl_polynomial_set_coeff(polybot, &k, coeff);
02122 }
02123
02124
02125
02126
02127
02128
02129 for (j = start_pixel; j < end_pixel; j++) {
02130 top = cpl_polynomial_eval_1d(polytop, j, NULL);
02131 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
02132 itop = floor(top + 0.5) + 1;
02133 ibot = floor(bot + 0.5);
02134 if (itop > ny)
02135 itop = ny;
02136 if (ibot < 0)
02137 ibot = 0;
02138 npix = itop - ibot;
02139 if (npix < 5)
02140 break;
02141
02142 list = cpl_bivector_new(npix);
02143 listx = cpl_bivector_get_x(list);
02144 listy = cpl_bivector_get_y(list);
02145 dlistx = cpl_vector_get_data(listx);
02146 dlisty = cpl_vector_get_data(listy);
02147
02148 for (k = 0; k < npix; k++) {
02149 dlistx[k] = k;
02150 dlisty[k] = sdata[j + (ibot + k)*nx];
02151 }
02152
02153 if (robustLinearFit(list, &q, &m, &err)) {
02154 cpl_bivector_delete(list);
02155 continue;
02156 }
02157
02158 cpl_bivector_delete(list);
02159
02160 for (k = 0; k < npix; k++) {
02161 kdata[j + (ibot + k)*nx] = m*k + q;
02162 }
02163
02164 if (npix > window) {
02165
02166
02167
02168
02169
02170 err = 3*sqrt(err);
02171
02172 count = 0;
02173 for (k = 0; k < npix; k++)
02174 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err)
02175 count++;
02176
02177 if (count < 10)
02178 continue;
02179
02180 list = cpl_bivector_new(count);
02181 listx = cpl_bivector_get_x(list);
02182 listy = cpl_bivector_get_y(list);
02183 dlistx = cpl_vector_get_data(listx);
02184 dlisty = cpl_vector_get_data(listy);
02185
02186 count = 0;
02187 for (k = 0; k < npix; k++) {
02188 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err) {
02189 dlistx[count] = k;
02190 dlisty[count] = sdata[j + (ibot + k)*nx];
02191 count++;
02192 }
02193 }
02194
02195 trend = cpl_polynomial_fit_1d_create(listx, listy, 2, &err);
02196
02197 cpl_bivector_delete(list);
02198
02199 err = 3*sqrt(err);
02200
02201 count = 0;
02202 for (k = 0; k < npix; k++)
02203 if (fabs(sdata[j + (ibot + k)*nx]
02204 - cpl_polynomial_eval_1d(trend, k, NULL)) < err)
02205 count++;
02206
02207 if (count < 10) {
02208 cpl_polynomial_delete(trend);
02209 continue;
02210 }
02211
02212 list = cpl_bivector_new(count);
02213 listx = cpl_bivector_get_x(list);
02214 listy = cpl_bivector_get_y(list);
02215 dlistx = cpl_vector_get_data(listx);
02216 dlisty = cpl_vector_get_data(listy);
02217
02218 count = 0;
02219 for (k = 0; k < npix; k++) {
02220 if (fabs(sdata[j + (ibot + k)*nx]
02221 - cpl_polynomial_eval_1d(trend, k, NULL)) < err) {
02222 dlistx[count] = k;
02223 dlisty[count] = sdata[j + (ibot + k)*nx];
02224 count++;
02225 }
02226 }
02227
02228 cpl_polynomial_delete(trend);
02229
02230 trend = cpl_polynomial_fit_1d_create(listx, listy, 3, &err);
02231
02232 cpl_bivector_delete(list);
02233
02234 for (k = 0; k < npix; k++) {
02235 kdata[j + (ibot + k)*nx] = cpl_polynomial_eval_1d(trend,
02236 k, NULL);
02237 }
02238
02239 cpl_polynomial_delete(trend);
02240 }
02241 }
02242 cpl_polynomial_delete(polytop);
02243 cpl_polynomial_delete(polybot);
02244 }
02245
02246 cpl_image_subtract(science, sky);
02247
02248 return sky;
02249 }
02250
02251
02284 cpl_image *mos_normalise_flat(cpl_image *flat, cpl_image *spatial,
02285 cpl_table *slits, cpl_table *polytraces,
02286 double reference, double blue, double red,
02287 double dispersion, int sradius, int polyorder)
02288 {
02289 const char *func = "mos_normalise_flat";
02290
02291 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
02292
02293
02294 cpl_image *rectified;
02295 cpl_image *smo_flat;
02296 cpl_image *exslit;
02297 cpl_vector *positions;
02298 cpl_vector *flux;
02299 cpl_vector *smo_flux;
02300 cpl_polynomial *trend;
02301 cpl_polynomial *polytop;
02302 cpl_polynomial *polybot;
02303
02304 int *slit_id;
02305 float *p;
02306 float *data;
02307 double *fdata;
02308 double *pdata;
02309 float *sdata;
02310 float *xdata;
02311 float *wdata;
02312 double vtop, vbot, value;
02313 double top, bot;
02314 double coeff;
02315 double ytop, ybot;
02316 double ypos;
02317 double fvalue;
02318 int ivalue;
02319 int yint, yprev;
02320 int npseudo;
02321
02322 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
02323 int nx, ny, nsubx, nsuby;
02324 int xlow, ylow, xhig, yhig;
02325 int nslits;
02326 int *position;
02327 int *length;
02328 int missing_top, missing_bot;
02329 int order;
02330 int npoints;
02331 int uradius;
02332 int null;
02333 int i, j, k;
02334
02335
02336
02337
02338
02339
02340 if (flat == NULL || slits == NULL || polytraces == NULL) {
02341 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02342 return NULL;
02343 }
02344
02345 if (dispersion <= 0.0) {
02346 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02347 return NULL;
02348 }
02349
02350 if (red - blue < dispersion) {
02351 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02352 return NULL;
02353 }
02354
02355 rectified = mos_spatial_calibration(flat, slits, polytraces, reference,
02356 blue, red, dispersion, 0, NULL);
02357
02358 nx = cpl_image_get_size_x(rectified);
02359 ny = cpl_image_get_size_y(rectified);
02360
02361 smo_flat = cpl_image_new(cpl_image_get_size_x(spatial),
02362 cpl_image_get_size_y(spatial), CPL_TYPE_FLOAT);
02363 wdata = cpl_image_get_data(smo_flat);
02364
02365 nslits = cpl_table_get_nrow(slits);
02366 order = cpl_table_get_ncol(polytraces) - 2;
02367 position = cpl_table_get_data_int(slits, "position");
02368 length = cpl_table_get_data_int(slits, "length");
02369 slit_id = cpl_table_get_data_int(slits, "slit_id");
02370
02371
02372
02373
02374
02375
02376 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
02377 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
02378
02379 xlow = 1;
02380 xhig = nx;
02381 for (i = 0; i < nslits; i++) {
02382
02383 if (length[i] == 0)
02384 continue;
02385
02386
02387
02388
02389
02390
02391
02392
02393
02394
02395
02396 ylow = position[i] + 1;
02397 yhig = ylow + length[i] - 1;
02398
02399 exslit = cpl_image_extract(rectified, xlow, ylow, xhig, yhig);
02400
02401 if (polyorder < 0) {
02402
02403 cpl_image_turn(exslit, -1);
02404
02405 nsubx = cpl_image_get_size_x(exslit);
02406 nsuby = cpl_image_get_size_y(exslit);
02407 data = cpl_image_get_data(exslit);
02408 flux = cpl_vector_new(nsubx);
02409
02410 uradius = nsubx / 2;
02411 if (uradius > sradius)
02412 uradius = sradius;
02413
02414 for (j = 0; j < nsuby; j++) {
02415 fdata = cpl_vector_get_data(flux);
02416 p = data;
02417 for (k = 0; k < nsubx; k++)
02418 *fdata++ = *p++;
02419 smo_flux = cpl_vector_filter_median_create(flux, uradius);
02420 fdata = cpl_vector_get_data(smo_flux);
02421 p = data;
02422 for (k = 0; k < nsubx; k++)
02423 *p++ = *fdata++;
02424 cpl_vector_delete(smo_flux);
02425 data += nsubx;
02426 }
02427
02428 cpl_vector_delete(flux);
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
02461
02462
02463
02464 cpl_image_turn(exslit, 1);
02465 nsubx = cpl_image_get_size_x(exslit);
02466 nsuby = cpl_image_get_size_y(exslit);
02467 data = cpl_image_get_data(exslit);
02468
02469 for (j = 0; j < nsuby; j++) {
02470 flux = cpl_vector_new(nsubx);
02471 fdata = cpl_vector_get_data(flux);
02472 p = data;
02473 for (k = 0; k < nsubx; k++)
02474 *fdata++ = *p++;
02475 smo_flux = cpl_vector_filter_median_create(flux, sradius);
02476 cpl_vector_delete(flux);
02477 fdata = cpl_vector_get_data(smo_flux);
02478 p = data;
02479 for (k = 0; k < nsubx; k++)
02480 *p++ = *fdata++;
02481 cpl_vector_delete(smo_flux);
02482 data += nsubx;
02483 }
02484 }
02485 else {
02486
02487
02488
02489
02490
02491 nsubx = cpl_image_get_size_x(exslit);
02492 nsuby = cpl_image_get_size_y(exslit);
02493 data = cpl_image_get_data(exslit);
02494
02495 for (j = 0; j < nsuby; j++) {
02496
02497
02498
02499
02500
02501 npoints = 0;
02502 p = data + j*nsubx;
02503 for (k = 0; k < nsubx; k++)
02504 if (p[k] > 1.0)
02505 npoints++;
02506
02507 if (npoints > polyorder + 1) {
02508
02509
02510
02511
02512
02513 flux = cpl_vector_new(npoints);
02514 fdata = cpl_vector_get_data(flux);
02515 positions = cpl_vector_new(npoints);
02516 pdata = cpl_vector_get_data(positions);
02517
02518 npoints = 0;
02519 p = data + j*nsubx;
02520 for (k = 0; k < nsubx; k++) {
02521 if (p[k] > 1.0) {
02522 fdata[npoints] = p[k];
02523 pdata[npoints] = k;
02524 npoints++;
02525 }
02526 }
02527
02528 trend = cpl_polynomial_fit_1d_create(positions, flux,
02529 polyorder, NULL);
02530
02531 cpl_vector_delete(flux);
02532 cpl_vector_delete(positions);
02533
02534 if (trend) {
02535 p = data + j*nsubx;
02536 for (k = 0; k < nsubx; k++)
02537 if (p[k] > 1.0)
02538 p[k] = cpl_polynomial_eval_1d(trend, k, NULL);
02539 cpl_polynomial_delete(trend);
02540 }
02541 else {
02542 cpl_msg_warning(func, "Invalid flat field flux fit "
02543 "(ignored)");
02544 }
02545 }
02546 }
02547 }
02548
02549
02550
02551
02552
02553
02554
02555 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
02556
02557 start_pixel = refpixel - pixel_below;
02558 if (start_pixel < 0)
02559 start_pixel = 0;
02560
02561 end_pixel = refpixel + pixel_above;
02562 if (end_pixel > nx)
02563 end_pixel = nx;
02564
02565 missing_top = 0;
02566 polytop = cpl_polynomial_new(1);
02567 for (k = 0; k <= order; k++) {
02568 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
02569 if (null) {
02570 cpl_polynomial_delete(polytop);
02571 missing_top = 1;
02572 break;
02573 }
02574 cpl_polynomial_set_coeff(polytop, &k, coeff);
02575 }
02576
02577 missing_bot = 0;
02578 polybot = cpl_polynomial_new(1);
02579 for (k = 0; k <= order; k++) {
02580 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
02581 if (null) {
02582 cpl_polynomial_delete(polybot);
02583 missing_bot = 1;
02584 break;
02585 }
02586 cpl_polynomial_set_coeff(polybot, &k, coeff);
02587 }
02588
02589 if (missing_top && missing_bot) {
02590 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
02591 slit_id[i]);
02592 continue;
02593 }
02594
02595
02596
02597
02598
02599
02600
02601 if (missing_top) {
02602 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
02603 "the spectral curvature of the lower edge "
02604 "is used instead.", slit_id[i]);
02605 polytop = cpl_polynomial_duplicate(polybot);
02606 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02607 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02608 k = 0;
02609 coeff = cpl_polynomial_get_coeff(polybot, &k);
02610 coeff += ytop - ybot;
02611 cpl_polynomial_set_coeff(polytop, &k, coeff);
02612 }
02613
02614 if (missing_bot) {
02615 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
02616 "the spectral curvature of the upper edge "
02617 "is used instead.", slit_id[i]);
02618 polybot = cpl_polynomial_duplicate(polytop);
02619 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02620 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02621 k = 0;
02622 coeff = cpl_polynomial_get_coeff(polytop, &k);
02623 coeff -= ytop - ybot;
02624 cpl_polynomial_set_coeff(polybot, &k, coeff);
02625 }
02626
02627
02628
02629
02630
02631
02632
02633
02634
02635 nx = cpl_image_get_size_x(flat);
02636 ny = cpl_image_get_size_y(flat);
02637
02638 sdata = cpl_image_get_data(spatial);
02639 xdata = cpl_image_get_data(exslit);
02640 npseudo = cpl_image_get_size_y(exslit) - 1;
02641
02642
02643
02644
02645
02646 for (j = start_pixel; j < end_pixel; j++) {
02647 top = cpl_polynomial_eval_1d(polytop, j, NULL);
02648 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
02649 for (k = 0; k <= npseudo; k++) {
02650 ypos = top - k*(top-bot)/npseudo;
02651 yint = ypos;
02652
02653
02654
02655
02656
02657
02658
02659
02660 if (yint < 0 || yint >= ny-1) {
02661 yprev = yint;
02662 continue;
02663 }
02664
02665 value = sdata[j + nx*yint];
02666 ivalue = value;
02667 fvalue = value - ivalue;
02668 if (ivalue < npseudo && ivalue >= 0) {
02669 vtop = xdata[j + nx*(npseudo-ivalue)];
02670 vbot = xdata[j + nx*(npseudo-ivalue-1)];
02671 wdata[j + nx*yint] = vtop*(1-fvalue) + vbot*fvalue;
02672
02673 if (k) {
02674
02675
02676
02677
02678
02679
02680
02681 if (yprev - yint > 1) {
02682 value = sdata[j + nx*(yint+1)];
02683 ivalue = value;
02684 fvalue = value - ivalue;
02685 if (ivalue < npseudo && ivalue >= 0) {
02686 vtop = xdata[j + nx*(npseudo-ivalue)];
02687 vbot = xdata[j + nx*(npseudo-ivalue-1)];
02688 wdata[j + nx*(yint+1)] = vtop*(1-fvalue)
02689 + vbot*fvalue;
02690 }
02691 }
02692 }
02693 }
02694 yprev = yint;
02695 }
02696 }
02697 cpl_polynomial_delete(polytop);
02698 cpl_polynomial_delete(polybot);
02699 cpl_image_delete(exslit);
02700 }
02701
02702 cpl_image_delete(rectified);
02703
02704 cpl_image_divide(flat, smo_flat);
02705
02706 return smo_flat;
02707 }
02708
02709
02734 cpl_image *mos_normalise_longflat(cpl_image *flat, int sradius, int dradius,
02735 int polyorder)
02736 {
02737 const char *func = "mos_normalise_longflat";
02738
02739 cpl_image *smo_flat;
02740 cpl_image *profile;
02741 cpl_vector *flux;
02742 cpl_vector *smo_flux;
02743 cpl_vector *positions;
02744 cpl_polynomial *trend;
02745
02746 float *level;
02747 float *p;
02748 float *data;
02749 double *fdata;
02750 double *pdata;
02751
02752 int nx, ny;
02753 int npoints;
02754 int i, j;
02755
02756
02757 if (flat == NULL) {
02758 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02759 return NULL;
02760 }
02761
02762 if (sradius < 1 || dradius < 1) {
02763 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02764 return NULL;
02765 }
02766
02767 smo_flat = cpl_image_duplicate(flat);
02768
02769 if (polyorder < 0) {
02770
02771
02772
02773
02774
02775 cpl_image_turn(smo_flat, -1);
02776
02777 nx = cpl_image_get_size_x(smo_flat);
02778 ny = cpl_image_get_size_y(smo_flat);
02779 data = cpl_image_get_data(smo_flat);
02780
02781 for (i = 0; i < ny; i++) {
02782 flux = cpl_vector_new(nx);
02783 fdata = cpl_vector_get_data(flux);
02784 p = data;
02785 for (j = 0; j < nx; j++)
02786 *fdata++ = *p++;
02787 smo_flux = cpl_vector_filter_median_create(flux, sradius);
02788 cpl_vector_delete(flux);
02789 fdata = cpl_vector_get_data(smo_flux);
02790 p = data;
02791 for (j = 0; j < nx; j++)
02792 *p++ = *fdata++;
02793 cpl_vector_delete(smo_flux);
02794 data += nx;
02795 }
02796
02797
02798
02799
02800
02801 cpl_image_turn(smo_flat, 1);
02802
02803 nx = cpl_image_get_size_x(smo_flat);
02804 ny = cpl_image_get_size_y(smo_flat);
02805 data = cpl_image_get_data(smo_flat);
02806
02807 for (i = 0; i < ny; i++) {
02808 flux = cpl_vector_new(nx);
02809 fdata = cpl_vector_get_data(flux);
02810 p = data;
02811 for (j = 0; j < nx; j++)
02812 *fdata++ = *p++;
02813 smo_flux = cpl_vector_filter_median_create(flux, sradius);
02814 cpl_vector_delete(flux);
02815 fdata = cpl_vector_get_data(smo_flux);
02816 p = data;
02817 for (j = 0; j < nx; j++)
02818 *p++ = *fdata++;
02819 cpl_vector_delete(smo_flux);
02820 data += nx;
02821 }
02822 }
02823 else {
02824
02825
02826
02827
02828
02829 cpl_image_turn(smo_flat, -1);
02830
02831 nx = cpl_image_get_size_x(smo_flat);
02832 ny = cpl_image_get_size_y(smo_flat);
02833 data = cpl_image_get_data(smo_flat);
02834
02835 profile = cpl_image_collapse_median_create(smo_flat, 1, 0, 0);
02836 level = cpl_image_get_data(profile);
02837
02838 for (i = 0; i < ny; i++) {
02839
02840
02841
02842
02843
02844
02845
02846 npoints = 0;
02847 p = data + i*nx;
02848 for (j = 0; j < nx; j++)
02849 if (fabs(p[j]/level[i] - 1) < 0.20)
02850 npoints++;
02851
02852 if (npoints > polyorder + 1) {
02853
02854
02855
02856
02857
02858 flux = cpl_vector_new(npoints);
02859 fdata = cpl_vector_get_data(flux);
02860 positions = cpl_vector_new(npoints);
02861 pdata = cpl_vector_get_data(positions);
02862
02863 npoints = 0;
02864 p = data + i*nx;
02865 for (j = 0; j < nx; j++) {
02866 if (fabs(p[j]/level[i] - 1) < 0.20) {
02867 fdata[npoints] = p[j];
02868 pdata[npoints] = j;
02869 npoints++;
02870 }
02871 }
02872
02873 trend = cpl_polynomial_fit_1d_create(positions, flux,
02874 polyorder, NULL);
02875
02876 cpl_vector_delete(flux);
02877 cpl_vector_delete(positions);
02878
02879 if (trend) {
02880 p = data + i*nx;
02881 for (j = 0; j < nx; j++)
02882 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
02883 cpl_polynomial_delete(trend);
02884 }
02885 else {
02886 cpl_msg_warning(func,
02887 "Invalid flat field flux fit (ignored)");
02888 }
02889 }
02890 }
02891
02892 cpl_image_delete(profile);
02893 cpl_image_turn(smo_flat, 1);
02894
02895 }
02896
02897 cpl_image_divide(flat, smo_flat);
02898
02899 return smo_flat;
02900 }
02901
02902
02925 cpl_error_code mos_interpolate_wavecalib_slit(cpl_table *idscoeff,
02926 cpl_table *slits,
02927 int order, int global)
02928 {
02929 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
02930
02931 int nrow = cpl_table_get_nrow(slits);
02932 int i, j;
02933
02934
02935 if (order < 0)
02936 return CPL_ERROR_NONE;
02937
02938 cpl_table_new_column(idscoeff, "x", CPL_TYPE_DOUBLE);
02939 cpl_table_new_column(idscoeff, "y", CPL_TYPE_DOUBLE);
02940
02941 for (i = 0; i < nrow; i++) {
02942 int position = cpl_table_get_int (slits, "position", i, NULL);
02943 int length = cpl_table_get_int (slits, "length", i, NULL);
02944 double xtop = cpl_table_get_double(slits, "xtop", i, NULL);
02945 double xbot = cpl_table_get_double(slits, "xbottom", i, NULL);
02946 double ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02947 double ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02948 double dx = xtop - xbot;
02949 double dy = ytop - ybot;
02950 cpl_table *table = cpl_table_extract(idscoeff, position, length);
02951
02952 if (mos_interpolate_wavecalib(table, NULL, 2, order))
02953 continue;
02954
02955 cpl_table_erase_window(idscoeff, position, length);
02956 cpl_table_insert(idscoeff, table, position);
02957
02958 cpl_table_delete(table);
02959
02960 for (j = 0; j < length; j++) {
02961 cpl_table_set_double(idscoeff, "x", j + position,
02962 xbot + j*(dx/length));
02963 cpl_table_set_double(idscoeff, "y", j + position,
02964 ybot + j*(dy/length));
02965 }
02966 }
02967
02968 if (global) {
02969
02970
02971
02972
02973
02974 nrow = cpl_table_get_nrow(idscoeff);
02975
02976 for (i = 0; i < 6; i++) {
02977 cpl_table *dummy;
02978 cpl_vector *x;
02979 cpl_vector *y;
02980 cpl_bivector *z;
02981 cpl_vector *c;
02982 cpl_polynomial *p;
02983 cpl_vector *point;
02984 double *dpoint;
02985 int npoints;
02986
02987 if (!cpl_table_has_column(idscoeff, clab[i]))
02988 break;
02989
02990 npoints = nrow - cpl_table_count_invalid(idscoeff, clab[i]);
02991 if (npoints < 18)
02992 break;
02993
02994 dummy = cpl_table_new(nrow);
02995 cpl_table_duplicate_column(dummy, "x", idscoeff, "x");
02996 cpl_table_duplicate_column(dummy, "y", idscoeff, "y");
02997 cpl_table_duplicate_column(dummy, clab[i], idscoeff, clab[i]);
02998 cpl_table_erase_invalid(dummy);
02999
03000 x = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy, "x"));
03001 y = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy, "y"));
03002 z = cpl_bivector_wrap_vectors(x, y);
03003 c = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy,
03004 clab[i]));
03005 p = cpl_polynomial_fit_2d_create(z, c, 2, NULL);
03006 cpl_bivector_unwrap_vectors(z);
03007 cpl_vector_unwrap(x);
03008 cpl_vector_unwrap(y);
03009 cpl_vector_unwrap(c);
03010 cpl_table_delete(dummy);
03011
03012 point = cpl_vector_new(2);
03013 dpoint = cpl_vector_get_data(point);
03014 for (j = 0; j < nrow; j++) {
03015 dpoint[0] = cpl_table_get_double(idscoeff, "x", j, NULL);
03016 dpoint[1] = cpl_table_get_double(idscoeff, "y", j, NULL);
03017 cpl_table_set_double(idscoeff, clab[i], j,
03018 cpl_polynomial_eval(p, point));
03019 }
03020 cpl_vector_delete(point);
03021 cpl_polynomial_delete(p);
03022 }
03023 }
03024
03025 return CPL_ERROR_NONE;
03026 }
03027
03028
03054 cpl_error_code mos_interpolate_wavecalib(cpl_table *idscoeff,
03055 cpl_image *wavemap, int mode,
03056 int degree)
03057 {
03058 const char *func = "mos_interpolate_wavecalib";
03059
03060 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
03061
03062
03063 cpl_vector *wave;
03064 cpl_vector *positions;
03065 cpl_polynomial *trend;
03066
03067 float *p;
03068 float *data;
03069 double *wdata;
03070 double *pdata;
03071
03072 double c;
03073 double mse, ksigma;
03074
03075 int order;
03076 int nrows, first_row, last_row;
03077 int nx, ny;
03078 int npoints, rpoints;
03079 int null;
03080 int i, j, k;
03081
03082 int polyorder = 4;
03083
03084
03085 if (idscoeff == NULL)
03086 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03087
03088 if (mode < 0 || mode > 2)
03089 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
03090
03091 if (mode == 0 || degree < 0)
03092 return CPL_ERROR_NONE;
03093
03094 if (wavemap) {
03095
03096
03097
03098
03099
03100 cpl_image_turn(wavemap, -1);
03101
03102 nx = cpl_image_get_size_x(wavemap);
03103 ny = cpl_image_get_size_y(wavemap);
03104 data = cpl_image_get_data(wavemap);
03105
03106 for (i = 0; i < ny; i++) {
03107
03108
03109
03110
03111
03112
03113 npoints = 0;
03114 p = data + i*nx;
03115 for (j = 0; j < nx; j++)
03116 if (p[j] > 1.0)
03117 npoints++;
03118
03119 if (npoints > polyorder + 1) {
03120
03121
03122
03123
03124
03125 wave = cpl_vector_new(npoints);
03126 wdata = cpl_vector_get_data(wave);
03127 positions = cpl_vector_new(npoints);
03128 pdata = cpl_vector_get_data(positions);
03129
03130 npoints = 0;
03131 p = data + i*nx;
03132 for (j = 0; j < nx; j++) {
03133 if (p[j] > 1.0) {
03134 wdata[npoints] = p[j];
03135 pdata[npoints] = j;
03136 npoints++;
03137 }
03138 }
03139
03140 trend = cpl_polynomial_fit_1d_create(positions, wave,
03141 polyorder, &mse);
03142
03143 ksigma = 3*sqrt(mse);
03144
03145 cpl_vector_delete(wave);
03146 cpl_vector_delete(positions);
03147
03148 if (trend) {
03149
03150
03151
03152
03153
03154 rpoints = 0;
03155 p = data + i*nx;
03156 for (j = 0; j < nx; j++)
03157 if (p[j] > 1.0)
03158 if (fabs(cpl_polynomial_eval_1d(trend, j, NULL)
03159 - p[j]) < ksigma)
03160 rpoints++;
03161
03162 if (rpoints < npoints && rpoints > polyorder + 1) {
03163
03164 wave = cpl_vector_new(rpoints);
03165 wdata = cpl_vector_get_data(wave);
03166 positions = cpl_vector_new(rpoints);
03167 pdata = cpl_vector_get_data(positions);
03168
03169 npoints = 0;
03170 p = data + i*nx;
03171 for (j = 0; j < nx; j++) {
03172 if (p[j] > 1.0) {
03173 if (fabs(cpl_polynomial_eval_1d(trend,
03174 j, NULL) - p[j])
03175 < ksigma) {
03176 wdata[npoints] = p[j];
03177 pdata[npoints] = j;
03178 npoints++;
03179 }
03180 }
03181 }
03182
03183 cpl_polynomial_delete(trend);
03184 trend = cpl_polynomial_fit_1d_create(positions, wave,
03185 polyorder, NULL);
03186
03187 cpl_vector_delete(wave);
03188 cpl_vector_delete(positions);
03189 }
03190 }
03191
03192 if (trend) {
03193 p = data + i*nx;
03194 if (mode == 1) {
03195 for (j = 0; j < nx; j++)
03196 if (p[j] < 1.0)
03197 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
03198 }
03199 else if (mode == 2) {
03200 for (j = 0; j < nx; j++)
03201 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
03202 }
03203 cpl_polynomial_delete(trend);
03204 }
03205 else {
03206 cpl_msg_warning(func,
03207 "Invalid wavelength field fit (ignored)");
03208 }
03209 }
03210
03211 }
03212
03213 cpl_image_turn(wavemap, 1);
03214
03215 }
03216
03217
03218
03219
03220
03221
03222 nrows = cpl_table_get_nrow(idscoeff);
03223
03224 order = 0;
03225 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
03226 ++order;
03227 --order;
03228
03229 if (degree == 0) {
03230 for (k = 0; k <= order; k++) {
03231 double m;
03232 if (cpl_table_has_column(idscoeff, clab[k])) {
03233 m = cpl_table_get_column_median(idscoeff, clab[k]);
03234 cpl_table_fill_column_window_double(idscoeff, clab[k],
03235 0, nrows, m);
03236 }
03237 }
03238
03239 return CPL_ERROR_NONE;
03240 }
03241
03242 first_row = 0;
03243 while (!cpl_table_is_valid(idscoeff, clab[0], first_row))
03244 first_row++;
03245
03246 last_row = nrows - 1;
03247 while (!cpl_table_is_valid(idscoeff, clab[0], last_row))
03248 last_row--;
03249
03250 for (k = 0; k <= order; k++) {
03251
03252 npoints = nrows - cpl_table_count_invalid(idscoeff, clab[k]);
03253 wave = cpl_vector_new(npoints);
03254 wdata = cpl_vector_get_data(wave);
03255 positions = cpl_vector_new(npoints);
03256 pdata = cpl_vector_get_data(positions);
03257
03258 npoints = 0;
03259 for (i = first_row; i <= last_row; i++) {
03260 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
03261 if (null == 0) {
03262 wdata[npoints] = c;
03263 pdata[npoints] = i;
03264 npoints++;
03265 }
03266 }
03267
03268
03269
03270
03271
03272
03273
03274
03275
03276
03277
03278
03279
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294
03295
03296
03297
03298
03299
03300
03301 trend = cpl_polynomial_fit_1d_create(positions, wave, degree, &mse);
03302
03303 ksigma = 3*sqrt(mse);
03304
03305 cpl_vector_delete(wave);
03306 cpl_vector_delete(positions);
03307
03308
03309
03310
03311
03312 if (trend) {
03313 rpoints = 0;
03314 for (i = first_row; i <= last_row; i++) {
03315 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
03316 if (null == 0) {
03317 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
03318 < ksigma) {
03319 rpoints++;
03320 }
03321 }
03322 }
03323
03324 if (rpoints > 0 && rpoints < npoints) {
03325 cpl_msg_debug(func, "%d points rejected from "
03326 "wavelength calibration fit",
03327 npoints - rpoints);
03328
03329 wave = cpl_vector_new(rpoints);
03330 wdata = cpl_vector_get_data(wave);
03331 positions = cpl_vector_new(rpoints);
03332 pdata = cpl_vector_get_data(positions);
03333
03334 npoints = 0;
03335 for (i = first_row; i <= last_row; i++) {
03336 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
03337 if (null == 0) {
03338 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
03339 < ksigma) {
03340 wdata[npoints] = c;
03341 pdata[npoints] = i;
03342 npoints++;
03343 }
03344 }
03345 }
03346
03347 if (npoints) {
03348 cpl_polynomial_delete(trend);
03349 trend = cpl_polynomial_fit_1d_create(positions,
03350 wave, degree, NULL);
03351 }
03352
03353 cpl_vector_delete(wave);
03354 cpl_vector_delete(positions);
03355
03356 }
03357 }
03358
03359 if (trend) {
03360 for (i = first_row; i <= last_row; i++) {
03361 if (mode == 1) {
03362 if (!cpl_table_is_valid(idscoeff, clab[k], i)) {
03363 cpl_table_set_double(idscoeff, clab[k], i,
03364 cpl_polynomial_eval_1d(trend, i,
03365 NULL));
03366 }
03367 }
03368 else if (mode == 2) {
03369 cpl_table_set_double(idscoeff, clab[k], i,
03370 cpl_polynomial_eval_1d(trend, i, NULL));
03371 }
03372 }
03373 cpl_polynomial_delete(trend);
03374 }
03375 else {
03376 cpl_msg_warning(func, "Invalid IDS coefficient fit (ignored)");
03377 }
03378
03379 }
03380
03381 return CPL_ERROR_NONE;
03382 }
03383
03384
03385
03411 cpl_image *mos_remove_bias(cpl_image *image, cpl_image *bias,
03412 cpl_table *overscans)
03413 {
03414 const char *func = "mos_remove_bias";
03415
03416 cpl_image *unbiased;
03417 cpl_image *overscan;
03418 double mean_bias_level;
03419 double mean_overscans_level;
03420 int count;
03421 int nrows;
03422 int xlow, ylow, xhig, yhig;
03423 int i;
03424
03425
03426 if (image == NULL || overscans == NULL) {
03427 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03428 return NULL;
03429 }
03430
03431 nrows = cpl_table_get_nrow(overscans);
03432
03433 if (nrows == 0) {
03434 cpl_msg_error(func, "Empty overscan table");
03435 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
03436 return NULL;
03437 }
03438
03439 if (bias) {
03440 if (nrows == 1) {
03441 unbiased = cpl_image_subtract_create(image, bias);
03442 if (unbiased == NULL) {
03443 cpl_msg_error(func, "Incompatible master bias");
03444 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03445 }
03446 return unbiased;
03447 }
03448 mean_bias_level = cpl_image_get_mean(bias);
03449 }
03450 else {
03451 if (nrows == 1) {
03452 cpl_msg_error(func, "No master bias in input, and no overscan "
03453 "regions in input image: bias subtraction "
03454 "cannot be performed!");
03455 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
03456 return NULL;
03457 }
03458 mean_bias_level = 0.0;
03459 }
03460
03461 mean_overscans_level = 0.0;
03462 count = 0;
03463 for (i = 0; i < nrows; i++) {
03464 xlow = cpl_table_get_int(overscans, "xlow", i, NULL);
03465 ylow = cpl_table_get_int(overscans, "ylow", i, NULL);
03466 xhig = cpl_table_get_int(overscans, "xhig", i, NULL);
03467 yhig = cpl_table_get_int(overscans, "yhig", i, NULL);
03468
03469 if (i == 0) {
03470 unbiased = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
03471 if (unbiased == NULL) {
03472 cpl_msg_error(func, "Incompatible overscan table");
03473 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03474 return NULL;
03475 }
03476 if (bias) {
03477 if (cpl_image_subtract(unbiased, bias)) {
03478 cpl_msg_error(func, "Incompatible master bias");
03479 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03480 cpl_image_delete(unbiased);
03481 return NULL;
03482 }
03483 }
03484 }
03485 else {
03486 overscan = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
03487 if (overscan == NULL) {
03488 cpl_msg_error(func, "Incompatible overscan table");
03489 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03490 cpl_image_delete(unbiased);
03491 return NULL;
03492 }
03493
03494 mean_overscans_level += cpl_image_get_median(overscan);
03495 count++;
03496
03497
03498
03499
03500
03501
03502
03503
03504 cpl_image_delete(overscan);
03505 }
03506 }
03507
03508
03509
03510
03511
03512 mean_overscans_level /= count;
03513
03514 cpl_image_subtract_scalar(unbiased, mean_overscans_level - mean_bias_level);
03515
03516 cpl_msg_info(cpl_func,
03517 "Ratio between mean overscans level and mean bias level: %.2f",
03518 mean_overscans_level / mean_bias_level);
03519
03520 return unbiased;
03521
03522 }
03523
03524
03583 cpl_error_code mos_arc_background_1D(float *spectrum, float *back,
03584 int length, int msize, int fsize)
03585 {
03586 const char *func = "mos_arc_background_1D";
03587
03588 float *minf;
03589 float *maxf;
03590 float *smof;
03591 int i;
03592
03593
03594 if (spectrum == NULL || back == NULL)
03595 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03596
03597 if (msize % 2 == 0)
03598 msize++;
03599
03600 if (fsize % 2 == 0)
03601 fsize++;
03602
03603 if (msize < 3 || fsize < msize || length < 2*fsize)
03604 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
03605
03606
03607 minf = min_filter(spectrum, length, msize);
03608 smof = smo_filter(minf, length, fsize);
03609 cpl_free(minf);
03610 maxf = max_filter(smof, length, 2*msize+1);
03611 cpl_free(smof);
03612 smof = smo_filter(maxf, length, 2*fsize+1);
03613 cpl_free(maxf);
03614 minf = min_filter(smof, length, 2*msize+1);
03615 cpl_free(smof);
03616 smof = smo_filter(minf, length, 2*fsize+1);
03617 cpl_free(minf);
03618
03619 for (i = 0; i < length; i++)
03620 back[i] = smof[i];
03621
03622 cpl_free(smof);
03623
03624 return CPL_ERROR_NONE;
03625
03626 }
03627
03628
03685 cpl_image *mos_arc_background(cpl_image *image, int msize, int fsize)
03686 {
03687 const char *func = "mos_arc_background";
03688
03689 cpl_image *fimage;
03690 cpl_image *bimage;
03691 cpl_matrix *kernel;
03692 float *data;
03693 float *bdata;
03694 float *row;
03695 float *brow;
03696 int nx, ny;
03697 int i;
03698
03699
03700 if (image == NULL) {
03701 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03702 return NULL;
03703 }
03704
03705 if (msize % 2 == 0)
03706 msize++;
03707
03708 if (fsize % 2 == 0)
03709 fsize++;
03710
03711 nx = cpl_image_get_size_x(image);
03712 ny = cpl_image_get_size_y(image);
03713
03714 bimage = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
03715
03716 fimage = mos_image_filter_median(image, 3, 3);
03717
03718 data = cpl_image_get_data_float(fimage);
03719 bdata = cpl_image_get_data_float(bimage);
03720
03721 for (i = 0; i < ny; i++) {
03722 row = data + i * nx;
03723 brow = bdata + i * nx;
03724 if (mos_arc_background_1D(row, brow, nx, msize, fsize)) {
03725 cpl_error_set_where(func);
03726 cpl_image_delete(fimage);
03727 cpl_image_delete(bimage);
03728 return NULL;
03729 }
03730 }
03731
03732 cpl_image_delete(fimage);
03733
03734 return bimage;
03735 }
03736
03737
03758 int mos_lines_width(const float *spectrum, int length)
03759 {
03760
03761 const char *func = "mos_lines_width";
03762
03763 double *profile1 = cpl_calloc(length - 1, sizeof(double));
03764 double *profile2 = cpl_calloc(length - 1, sizeof(double));
03765
03766 double norm, value, max;
03767 int radius = 20;
03768 int short_length = length - 2*radius - 1;
03769 int width;
03770 int i, j, k;
03771
03772
03773
03774
03775
03776
03777 for (j = 0, i = 1; i < length; j++, i++) {
03778 profile1[j] = profile2[j] = spectrum[i] - spectrum[j];
03779 if (profile1[j] < 0)
03780 profile1[j] = 0;
03781 if (profile2[j] > 0)
03782 profile2[j] = 0;
03783 else
03784 profile2[j] = -profile2[j];
03785 }
03786
03787
03788
03789
03790
03791
03792 length--;
03793
03794 norm = 0;
03795 for (i = 0; i < length; i++)
03796 if (norm < profile1[i])
03797 norm = profile1[i];
03798
03799 for (i = 0; i < length; i++) {
03800 profile1[i] /= norm;
03801 profile2[i] /= norm;
03802 }
03803
03804
03805
03806
03807
03808
03809 max = -1;
03810 for (i = 0; i <= radius; i++) {
03811 value = 0;
03812 for (j = 0; j < short_length; j++) {
03813 k = radius+j;
03814 value += profile1[k] * profile2[k+i];
03815 }
03816 if (max < value) {
03817 max = value;
03818 width = i;
03819 }
03820 }
03821
03822 cpl_free(profile1);
03823 cpl_free(profile2);
03824
03825 if (max < 0.0) {
03826 cpl_msg_debug(func, "Cannot estimate line width");
03827 width = 1;
03828 }
03829
03830 return width;
03831
03832 }
03833
03834
03861 cpl_vector *mos_peak_candidates(const float *spectrum,
03862 int length, float level,
03863 float exp_width)
03864 {
03865
03866 const char *func = "mos_peak_candidates";
03867
03868 int i, j;
03869 int nint = length - 1;
03870 int n = 0;
03871 int width = 2 * ceil(exp_width / 2) + 1;
03872 int start = width / 2;
03873 int end = length - width / 2;
03874 int step;
03875 float *smo;
03876 double *data = cpl_calloc(length/2, sizeof(double));
03877
03878
03879 if (spectrum == NULL) {
03880 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03881 return NULL;
03882 }
03883
03884
03885
03886
03887
03888
03889
03890 if (width > 7) {
03891 smo = cpl_calloc(length, sizeof(float));
03892 start = width / 2;
03893 end = length - width / 2;
03894 for (i = 0; i < start; i++)
03895 smo[i] = spectrum[i];
03896 for (i = start; i < end; i++) {
03897 for (j = i - start; j <= i + start; j++)
03898 smo[i] += spectrum[j];
03899 smo[i] /= width;
03900 }
03901 for (i = end; i < length; i++)
03902 smo[i] = spectrum[i];
03903 }
03904 else {
03905 smo = (float *)spectrum;
03906 }
03907
03908
03909
03910
03911
03912
03913 if (width > 20)
03914 step = width / 2;
03915 else
03916 step = 1;
03917
03918 for (i = step; i < nint - step + 1; i += step) {
03919 if (smo[i] > level) {
03920 if (smo[i] >= smo[i-step] && smo[i] > smo[i+step]) {
03921 if (smo[i-step] != 0.0 && smo[i+step] != 0.0) {
03922 data[n] = i + step * values_to_dx(smo[i-step], smo[i], smo[i+step]);
03923 ++n;
03924 }
03925 }
03926 }
03927 }
03928
03929 if (width > 7) {
03930 cpl_free(smo);
03931 }
03932
03933 if (n == 0) {
03934 cpl_free(data);
03935 return NULL;
03936 }
03937
03938 return cpl_vector_wrap(n, data);
03939
03940 }
03941
03942
03964 cpl_vector *mos_refine_peaks(const float *spectrum, int length,
03965 cpl_vector *peaks, int sradius)
03966 {
03967
03968 const char *func = "mos_refine_peaks";
03969
03970 double *data;
03971 float pos;
03972 int npeaks;
03973 int startPos, endPos;
03974 int window = 2*sradius+1;
03975 int i, j;
03976
03977
03978 if (peaks == NULL || spectrum == NULL) {
03979 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03980 return NULL;
03981 }
03982
03983 npeaks = cpl_vector_get_size(peaks);
03984 data = cpl_vector_unwrap(peaks);
03985
03986 for (i = 0; i < npeaks; i++) {
03987 startPos = data[i] - window/2;
03988 endPos = startPos + window;
03989 if (startPos < 0 || endPos >= length)
03990 continue;
03991
03992 if (0 == peakPosition(spectrum + startPos, window, &pos, 1)) {
03993 pos += startPos;
03994 data[i] = pos;
03995 }
03996 }
03997
03998 for (i = 1; i < npeaks; i++)
03999 if (data[i] - data[i-1] < 0.5)
04000 data[i-1] = -1.0;
04001
04002 for (i = 0, j = 0; i < npeaks; i++) {
04003 if (data[i] > 0.0) {
04004 if (i != j)
04005 data[j] = data[i];
04006 j++;
04007 }
04008 }
04009
04010 return cpl_vector_wrap(j, data);
04011
04012 }
04013
04014
04015 void mos_set_multiplex(int multiplex)
04016 {
04017 mos_multiplex = multiplex;
04018 }
04019
04073 cpl_bivector *mos_identify_peaks(cpl_vector *peaks, cpl_vector *lines,
04074 double min_disp, double max_disp,
04075 double tolerance)
04076 {
04077
04078 int i, j, k, l;
04079 int nlint, npint;
04080 int minpos;
04081 float min;
04082 double lratio, pratio;
04083 double lo_start, lo_end, hi_start, hi_end, denom;
04084 double disp, variation, prev_variation;
04085 int max, maxpos, minl, mink;
04086 int ambiguous;
04087 int npeaks_lo, npeaks_hi;
04088 int *peak_lo;
04089 int *peak_hi;
04090 int **ident;
04091 int *nident;
04092 int *lident;
04093
04094 double *peak;
04095 double *line;
04096 int npeaks, nlines;
04097
04098 double *xpos;
04099 double *lambda;
04100 int *ilambda;
04101 double *tmp_xpos;
04102 double *tmp_lambda;
04103 int *tmp_ilambda;
04104 int *flag;
04105 int n = 0;
04106 int nn;
04107 int nseq = 0;
04108 int gap;
04109 int *seq_length;
04110 int found;
04111
04112 peak = cpl_vector_get_data(peaks);
04113 npeaks = cpl_vector_get_size(peaks);
04114 line = cpl_vector_get_data(lines);
04115 nlines = cpl_vector_get_size(lines);
04116
04117 if (npeaks < 4)
04118 return NULL;
04119
04120 peak_lo = cpl_malloc(npeaks * sizeof(int));
04121 peak_hi = cpl_malloc(npeaks * sizeof(int));
04122 nident = cpl_calloc(npeaks, sizeof(int));
04123 lident = cpl_calloc(nlines, sizeof(int));
04124 xpos = cpl_calloc(npeaks, sizeof(double));
04125 lambda = cpl_calloc(npeaks, sizeof(double));
04126 ilambda = cpl_calloc(npeaks, sizeof(int));
04127 tmp_xpos = cpl_calloc(npeaks, sizeof(double));
04128 tmp_lambda = cpl_calloc(npeaks, sizeof(double));
04129 tmp_ilambda = cpl_calloc(npeaks, sizeof(int));
04130 flag = cpl_calloc(npeaks, sizeof(int));
04131 seq_length = cpl_calloc(npeaks, sizeof(int));
04132 ident = cpl_malloc(npeaks * sizeof(int *));
04133 for (i = 0; i < npeaks; i++)
04134 ident[i] = cpl_malloc(3 * npeaks * sizeof(int));
04135
04136
04137
04138
04139
04140
04141 nlint = nlines - 1;
04142 npint = npeaks - 1;
04143
04144
04145
04146
04147
04148
04149 for (i = 1; i < nlint; i++) {
04150
04151
04152
04153
04154
04155
04156
04157
04158
04159 lratio = (line[i+1] - line[i]) / (line[i] - line[i-1]);
04160
04161
04162
04163
04164
04165
04166 for (j = 1; j < npint; j++) {
04167
04168
04169
04170
04171
04172
04173
04174
04175
04176
04177
04178
04179 lo_start = peak[j] - (line[i] - line[i-1]) / min_disp;
04180 lo_end = peak[j] - (line[i] - line[i-1]) / max_disp;
04181 hi_start = peak[j] + (line[i+1] - line[i]) / max_disp;
04182 hi_end = peak[j] + (line[i+1] - line[i]) / min_disp;
04183
04184 for (npeaks_lo = 0, k = 0; k < npeaks; k++) {
04185 if (peak[k] > lo_end)
04186 break;
04187 if (peak[k] > lo_start) {
04188 peak_lo[npeaks_lo] = k;
04189 ++npeaks_lo;
04190 }
04191 }
04192
04193 if (npeaks_lo == 0)
04194 continue;
04195
04196 for (npeaks_hi = 0, k = 0; k < npeaks; k++) {
04197 if (peak[k] > hi_end)
04198 break;
04199 if (peak[k] > hi_start) {
04200 peak_hi[npeaks_hi] = k;
04201 ++npeaks_hi;
04202 }
04203 }
04204
04205 if (npeaks_hi == 0)
04206 continue;
04207
04208
04209
04210
04211
04212
04213
04214
04215
04216
04217 prev_variation = 1000.0;
04218 minl = mink = 0;
04219
04220 for (k = 0; k < npeaks_lo; k++) {
04221 denom = peak[j] - peak[peak_lo[k]];
04222 for (l = 0; l < npeaks_hi; l++) {
04223
04224
04225
04226
04227
04228
04229
04230 pratio = (peak[peak_hi[l]] - peak[j]) / denom;
04231
04232
04233
04234
04235
04236
04237
04238
04239
04240
04241
04242
04243 variation = fabs(lratio-pratio) / pratio;
04244
04245 if (variation < tolerance) {
04246 if (variation < prev_variation) {
04247 prev_variation = variation;
04248 minl = l;
04249 mink = k;
04250 }
04251 }
04252 }
04253 }
04254 if (prev_variation < tolerance) {
04255 ident[j][nident[j]] = i;
04256 ident[peak_hi[minl]][nident[peak_hi[minl]]] = i + 1;
04257 ident[peak_lo[mink]][nident[peak_lo[mink]]] = i - 1;
04258 ++nident[j];
04259 ++nident[peak_hi[minl]];
04260 ++nident[peak_lo[mink]];
04261 }
04262 }
04263 }
04264
04265
04266
04267
04268
04269
04270
04271
04272 for (i = 0; i < npeaks; i++) {
04273
04274
04275
04276
04277
04278
04279
04280
04281 if (nident[i] > 1) {
04282
04283
04284
04285
04286
04287
04288 for (j = 0; j < nlines; j++)
04289 lident[j] = 0;
04290
04291
04292
04293
04294
04295
04296
04297 for (j = 0; j < nident[i]; j++)
04298 ++lident[ident[i][j]];
04299
04300
04301
04302
04303
04304
04305 max = 0;
04306 maxpos = 0;
04307 for (j = 0; j < nlines; j++) {
04308 if (max < lident[j]) {
04309 max = lident[j];
04310 maxpos = j;
04311 }
04312 }
04313
04314
04315
04316
04317
04318
04319
04320
04321 ambiguous = 0;
04322
04323 for (k = maxpos + 1; k < nlines; k++) {
04324 if (lident[k] == max) {
04325 ambiguous = 1;
04326 break;
04327 }
04328 }
04329
04330 if (ambiguous)
04331 continue;
04332
04333
04334
04335
04336
04337
04338
04339 tmp_xpos[n] = peak[i];
04340 tmp_lambda[n] = line[maxpos];
04341 tmp_ilambda[n] = maxpos;
04342
04343 ++n;
04344
04345 }
04346
04347 }
04348
04349
04350
04351
04352
04353
04354
04355
04356
04357
04358
04359
04360
04361
04362 if (n > 1) {
04363 nn = 0;
04364 nseq = 0;
04365 for (k = 0; k < n; k++) {
04366 if (flag[k] == 0) {
04367 flag[k] = 1;
04368 xpos[nn] = tmp_xpos[k];
04369 lambda[nn] = tmp_lambda[k];
04370 ilambda[nn] = tmp_ilambda[k];
04371 ++seq_length[nseq];
04372 ++nn;
04373
04374
04375
04376
04377
04378
04379
04380 i = k;
04381 while (i < n - 1) {
04382 found = 0;
04383 for (j = i + 1; j < n; j++) {
04384 if (flag[j] == 0) {
04385 disp = (tmp_lambda[j] - tmp_lambda[i])
04386 / (tmp_xpos[j] - tmp_xpos[i]);
04387 if (disp >= min_disp && disp <= max_disp) {
04388 flag[j] = 1;
04389 xpos[nn] = tmp_xpos[j];
04390 lambda[nn] = tmp_lambda[j];
04391 ilambda[nn] = tmp_ilambda[j];
04392 ++seq_length[nseq];
04393 ++nn;
04394 i = j;
04395 found = 1;
04396 break;
04397 }
04398 }
04399 }
04400 if (!found)
04401 break;
04402 }
04403
04404
04405
04406
04407
04408
04409 ++nseq;
04410 k = 0;
04411 }
04412 }
04413
04414
04415
04416
04417
04418
04419 maxpos = max = 0;
04420
04421 if (mos_multiplex < 0) {
04422 for (i = 0; i < nseq; i++) {
04423 if (seq_length[i] > max) {
04424 max = seq_length[i];
04425 maxpos = i;
04426 }
04427 }
04428 }
04429 else {
04430
04431
04432
04433
04434
04435
04436
04437 nn = 0;
04438 found = 0;
04439
04440 for (i = 0; i < nseq; i++) {
04441 n = seq_length[i];
04442 if (n > 5) {
04443 cpl_array *regions = cpl_array_new(n, CPL_TYPE_INT);
04444 int region;
04445
04446 for (j = 0; j < n; j++)
04447 cpl_array_set_int(regions, j,
04448 ((int)floor(xpos[nn + j])) / mos_region_size);
04449
04450 region = (int)cpl_array_get_median(regions);
04451 cpl_array_delete(regions);
04452
04453 if (mos_multiplex == region) {
04454 if (found) {
04455 cpl_msg_debug(cpl_func, "More than one spectrum found in "
04456 "region %d (only the first one is extracted)",
04457 mos_multiplex);
04458 break;
04459 }
04460 found = 1;
04461 max = seq_length[i];
04462 maxpos = i;
04463 }
04464 }
04465 nn += seq_length[i];
04466 }
04467 }
04468
04469
04470
04471
04472
04473
04474 nn = 0;
04475 for (i = 0; i < maxpos; i++)
04476 nn += seq_length[i];
04477
04478
04479
04480
04481
04482 n = max;
04483 for (i = 0; i < n; i++, nn++) {
04484 xpos[i] = xpos[nn];
04485 lambda[i] = lambda[nn];
04486 ilambda[i] = ilambda[nn];
04487 }
04488
04489
04490
04491
04492
04493
04494 for (i = 1; i < n; i++) {
04495 gap = ilambda[i] - ilambda[i-1];
04496 for (j = 1; j < gap; j++) {
04497
04498 if (j == 1) {
04499
04500
04501
04502
04503
04504 disp = (lambda[i] - lambda[i-1]) / (xpos[i] - xpos[i-1]);
04505 }
04506
04507
04508
04509
04510
04511
04512 hi_start = xpos[i-1] + (line[ilambda[i-1] + j] - lambda[i-1]) / disp;
04513
04514
04515
04516
04517
04518
04519
04520
04521
04522
04523
04524
04525
04526 found = 0;
04527 for (k = 0; k < npeaks; k++) {
04528 if (fabs(peak[k] - hi_start) < 2) {
04529 for (l = n; l > i; l--) {
04530 xpos[l] = xpos[l-1];
04531 lambda[l] = lambda[l-1];
04532 ilambda[l] = ilambda[l-1];
04533 }
04534 xpos[i] = peak[k];
04535 lambda[i] = line[ilambda[i-1] + j];
04536 ilambda[i] = ilambda[i-1] + j;
04537 ++n;
04538 found = 1;
04539 break;
04540 }
04541 }
04542 if (found)
04543 break;
04544 }
04545 }
04546
04547
04548
04549
04550
04551
04552 found = 1;
04553 while (ilambda[n-1] < nlines - 1 && found) {
04554
04555
04556
04557
04558
04559
04560 if (n > 1)
04561 disp = (lambda[n-1] - lambda[n-2]) / (xpos[n-1] - xpos[n-2]);
04562 else
04563 disp = 0.0;
04564
04565 if (disp > max_disp || disp < min_disp)
04566 break;
04567
04568
04569
04570
04571
04572
04573
04574 hi_start = xpos[n-1] + (line[ilambda[n-1] + 1] - lambda[n-1]) / disp;
04575
04576
04577
04578
04579
04580
04581
04582
04583
04584 found = 0;
04585 min = fabs(peak[0] - hi_start);
04586 minpos = 0;
04587 for (k = 1; k < npeaks; k++) {
04588 if (min > fabs(peak[k] - hi_start)) {
04589 min = fabs(peak[k] - hi_start);
04590 minpos = k;
04591 }
04592 }
04593 if (min < 6 && fabs(peak[minpos] - xpos[n-1]) > 1.0) {
04594 xpos[n] = peak[minpos];
04595 lambda[n] = line[ilambda[n-1] + 1];
04596 ilambda[n] = ilambda[n-1] + 1;
04597 ++n;
04598 found = 1;
04599 }
04600 }
04601
04602
04603
04604
04605
04606
04607 found = 1;
04608 while (ilambda[0] > 0 && found) {
04609
04610
04611
04612
04613
04614
04615 disp = (lambda[1] - lambda[0]) / (xpos[1] - xpos[0]);
04616
04617 if (disp > max_disp || disp < min_disp)
04618 break;
04619
04620
04621
04622
04623
04624
04625
04626 hi_start = xpos[0] - (lambda[0] - line[ilambda[0] - 1]) / disp;
04627
04628
04629
04630
04631
04632
04633
04634
04635
04636
04637 found = 0;
04638 min = fabs(peak[0] - hi_start);
04639 minpos = 0;
04640 for (k = 1; k < npeaks; k++) {
04641 if (min > fabs(peak[k] - hi_start)) {
04642 min = fabs(peak[k] - hi_start);
04643 minpos = k;
04644 }
04645 }
04646 if (min < 6 && fabs(peak[minpos] - xpos[0]) > 1.0) {
04647 for (j = n; j > 0; j--) {
04648 xpos[j] = xpos[j-1];
04649 lambda[j] = lambda[j-1];
04650 ilambda[j] = ilambda[j-1];
04651 }
04652 xpos[0] = peak[minpos];
04653 lambda[0] = line[ilambda[0] - 1];
04654 ilambda[0] = ilambda[0] - 1;
04655 ++n;
04656 found = 1;
04657 }
04658 }
04659 }
04660
04661
04662
04663
04664
04665
04666
04667
04668
04669
04670
04671
04672
04673
04674
04675
04676
04677
04678
04679
04680 for (i = 0; i < npeaks; i++)
04681 cpl_free(ident[i]);
04682 cpl_free(ident);
04683 cpl_free(nident);
04684 cpl_free(lident);
04685 cpl_free(ilambda);
04686 cpl_free(tmp_xpos);
04687 cpl_free(tmp_lambda);
04688 cpl_free(tmp_ilambda);
04689 cpl_free(peak_lo);
04690 cpl_free(flag);
04691 cpl_free(seq_length);
04692 cpl_free(peak_hi);
04693
04694 if (n == 0) {
04695 cpl_free(xpos);
04696 cpl_free(lambda);
04697 return NULL;
04698 }
04699
04700 return cpl_bivector_wrap_vectors(cpl_vector_wrap(n, xpos),
04701 cpl_vector_wrap(n, lambda));
04702 }
04703
04704
04722
04723
04724
04725
04726
04727
04728
04729
04730
04731
04732
04733
04734
04735
04736
04737
04738
04739
04740
04741
04742
04743
04744
04745
04746
04747
04748
04749
04750
04751
04752
04753
04754
04755
04756
04757
04758
04759
04760
04761
04762 double mos_eval_dds(cpl_polynomial *ids, double blue, double red,
04763 double refwave, double pixel)
04764 {
04765 double yellow;
04766 double coeff;
04767 int zero = 0;
04768
04769 if (cpl_polynomial_eval_1d(ids, blue-refwave, NULL) > pixel)
04770 return 0.0;
04771
04772 if (cpl_polynomial_eval_1d(ids, red-refwave, NULL) < pixel)
04773 return 0.0;
04774
04775 yellow = (blue + red) / 2 - refwave;
04776
04777 coeff = cpl_polynomial_get_coeff(ids, &zero);
04778 cpl_polynomial_set_coeff(ids, &zero, coeff - pixel);
04779
04780 cpl_polynomial_solve_1d(ids, yellow, &yellow, 1);
04781 if (cpl_error_get_code() != CPL_ERROR_NONE) {
04782 cpl_error_reset();
04783 return 0.0;
04784 }
04785
04786 cpl_polynomial_set_coeff(ids, &zero, coeff);
04787
04788 return yellow + refwave;
04789
04790 }
04791
04817 cpl_polynomial *mos_poly_wav2pix(cpl_bivector *pixwav, int order,
04818 double reject, int minlines,
04819 int *nlines, double *err)
04820 {
04821 const char *func = "mos_poly_wav2pix";
04822
04823 cpl_bivector *pixwav2;
04824 cpl_vector *wavel;
04825 cpl_vector *pixel;
04826 double *d_wavel;
04827 double *d_pixel;
04828 double pixpos;
04829 int fitlines;
04830 int rejection = 0;
04831 int i, j;
04832
04833 cpl_polynomial *ids;
04834
04835
04836 *nlines = 0;
04837 *err = 0;
04838
04839 if (pixwav == NULL) {
04840 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
04841 return NULL;
04842 }
04843
04844 fitlines = cpl_bivector_get_size(pixwav);
04845
04846 if (fitlines < minlines) {
04847 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
04848 return NULL;
04849 }
04850
04851
04852
04853
04854
04855
04856
04857 if (reject > 0.0)
04858 rejection = 1;
04859
04860 if (rejection)
04861 pixwav2 = cpl_bivector_duplicate(pixwav);
04862 else
04863 pixwav2 = pixwav;
04864
04865
04866
04867
04868
04869
04870
04871 pixel = cpl_bivector_get_x(pixwav2);
04872 wavel = cpl_bivector_get_y(pixwav2);
04873
04874
04875
04876
04877
04878
04879 if (rejection)
04880 cpl_bivector_unwrap_vectors(pixwav2);
04881
04882
04883
04884
04885
04886
04887 while (fitlines >= minlines) {
04888
04889 ids = cpl_polynomial_fit_1d_create(wavel, pixel, order, err);
04890 *err = sqrt(*err);
04891
04892 if (ids == NULL) {
04893 cpl_msg_debug(cpl_error_get_where(), cpl_error_get_message());
04894 cpl_msg_debug(func, "Fitting IDS");
04895 cpl_error_set_where(func);
04896 if (rejection) {
04897 cpl_vector_delete(wavel);
04898 cpl_vector_delete(pixel);
04899 }
04900 return NULL;
04901 }
04902
04903 if (rejection) {
04904
04905
04906
04907
04908
04909
04910 d_pixel = cpl_vector_unwrap(pixel);
04911 d_wavel = cpl_vector_unwrap(wavel);
04912
04913 for (i = 0, j = 0; i < fitlines; i++) {
04914 pixpos = cpl_polynomial_eval_1d(ids, d_wavel[i], NULL);
04915 if (fabs(pixpos - d_pixel[i]) < reject) {
04916 d_pixel[j] = d_pixel[i];
04917 d_wavel[j] = d_wavel[i];
04918 j++;
04919 }
04920 }
04921
04922 if (j == fitlines) {
04923 cpl_free(d_wavel);
04924 cpl_free(d_pixel);
04925 *nlines = fitlines;
04926 return ids;
04927 }
04928 else {
04929 fitlines = j;
04930 cpl_polynomial_delete(ids);
04931 if (fitlines >= minlines) {
04932 pixel = cpl_vector_wrap(fitlines, d_pixel);
04933 wavel = cpl_vector_wrap(fitlines, d_wavel);
04934 }
04935 else {
04936 cpl_free(d_wavel);
04937 cpl_free(d_pixel);
04938 cpl_error_set(func, CPL_ERROR_CONTINUE);
04939 return NULL;
04940 }
04941 }
04942 }
04943 else {
04944 *nlines = fitlines;
04945 return ids;
04946 }
04947 }
04948
04949 return ids;
04950 }
04951
04952
04977 cpl_polynomial *mos_poly_pix2wav(cpl_bivector *pixwav, int order,
04978 double reject, int minlines,
04979 int *nlines, double *err)
04980 {
04981
04982 cpl_bivector *wavpix;
04983 cpl_vector *wavel;
04984 cpl_vector *pixel;
04985
04986 cpl_polynomial *dds;
04987
04988
04989
04990
04991
04992
04993 pixel = cpl_bivector_get_x(pixwav);
04994 wavel = cpl_bivector_get_y(pixwav);
04995
04996 wavpix = cpl_bivector_wrap_vectors(wavel, pixel);
04997
04998 dds = mos_poly_wav2pix(wavpix, order, reject, minlines, nlines, err);
04999
05000 cpl_bivector_unwrap_vectors(wavpix);
05001
05002 return dds;
05003
05004 }
05005
05006
05029 cpl_bivector *mos_find_peaks(const float *spectrum, int length,
05030 cpl_vector *lines, cpl_polynomial *ids,
05031 double refwave, int sradius)
05032 {
05033 const char *func = "mos_find_peaks";
05034
05035 double *data;
05036 double *d_pixel;
05037 double *d_wavel;
05038 float pos;
05039 int nlines;
05040 int pixel;
05041 int i, j;
05042
05043
05044 if (spectrum == NULL || lines == NULL || ids == NULL) {
05045 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05046 return NULL;
05047 }
05048
05049 nlines = cpl_vector_get_size(lines);
05050
05051 if (sradius < 1 || length < 2*sradius+1 || nlines < 1) {
05052 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05053 return NULL;
05054 }
05055
05056 d_wavel = cpl_malloc(nlines * sizeof(double));
05057 d_pixel = cpl_malloc(nlines * sizeof(double));
05058
05059 data = cpl_vector_get_data(lines);
05060
05061 for (i = 0, j = 0; i < nlines; i++) {
05062 pixel = cpl_polynomial_eval_1d(ids, data[i]-refwave, NULL) + 0.5;
05063 if (pixel - sradius < 0 || pixel + sradius >= length)
05064 continue;
05065 if (0 == peakPosition(spectrum+pixel-sradius, 2*sradius+1, &pos, 1)) {
05066 pos += pixel - sradius;
05067 d_pixel[j] = pos;
05068 d_wavel[j] = data[i];
05069 j++;
05070 }
05071 }
05072
05073 if (j > 0) {
05074 return cpl_bivector_wrap_vectors(cpl_vector_wrap(j, d_pixel),
05075 cpl_vector_wrap(j, d_wavel));
05076 }
05077 else {
05078 cpl_free(d_wavel);
05079 cpl_free(d_pixel);
05080 cpl_error_set(func, CPL_ERROR_ILLEGAL_OUTPUT);
05081 return NULL;
05082 }
05083 }
05084
05085
05203 cpl_image *mos_wavelength_calibration_raw(const cpl_image *image,
05204 cpl_vector *lines,
05205 double dispersion, float level,
05206 int sradius, int order,
05207 double reject, double refwave,
05208 double *wavestart, double *waveend,
05209 int *nlines, double *error,
05210 cpl_table *idscoeff,
05211 cpl_image *calibration,
05212 cpl_image *residuals,
05213 cpl_table *restable,
05214 cpl_mask *refmask)
05215 {
05216
05217 const char *func = "mos_wavelength_calibration_raw";
05218
05219 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
05220
05221
05222 double tolerance = 20.0;
05223 int step = 10;
05224
05225 char name[MAX_COLNAME];
05226 cpl_image *resampled;
05227 cpl_bivector *output;
05228 cpl_bivector *new_output;
05229 cpl_vector *peaks;
05230 cpl_vector *wavel;
05231 cpl_polynomial *ids;
05232 cpl_polynomial *lin;
05233 cpl_matrix *kernel;
05234 double ids_err;
05235 double max_disp, min_disp;
05236 double *line;
05237 double firstLambda, lastLambda, lambda;
05238 double value, wave, pixe;
05239 cpl_binary *mdata;
05240 const float *sdata;
05241 float *rdata;
05242 float *idata;
05243 float *ddata;
05244 float v1, v2, vi;
05245 float fpixel;
05246 int *have_it;
05247 int pixstart, pixend;
05248 int extrapolation;
05249 int nref;
05250 int nl, nx, ny, pixel;
05251 int countLines, usedLines;
05252 int uorder;
05253 int in, first, last;
05254 int width, uradius;
05255 int i, j, k;
05256
05257
05258 if (dispersion == 0.0) {
05259 cpl_msg_error(func, "The expected dispersion (A/pixel) must be given");
05260 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05261 return NULL;
05262 }
05263
05264 if (dispersion < 0.0) {
05265 cpl_msg_error(func, "The expected dispersion must be positive");
05266 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05267 return NULL;
05268 }
05269
05270 max_disp = dispersion + dispersion * tolerance / 100;
05271 min_disp = dispersion - dispersion * tolerance / 100;
05272
05273 if (order < 1) {
05274 cpl_msg_error(func, "The order of the fitting polynomial "
05275 "must be at least 1");
05276 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05277 return NULL;
05278 }
05279
05280 if (image == NULL || lines == NULL) {
05281 cpl_msg_error(func, "Both spectral exposure and reference line "
05282 "catalog are required in input");
05283 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05284 return NULL;
05285 }
05286
05287 nx = cpl_image_get_size_x(image);
05288 ny = cpl_image_get_size_y(image);
05289 sdata = cpl_image_get_data_float_const(image);
05290
05291 nref = cpl_vector_get_size(lines);
05292 line = cpl_vector_get_data(lines);
05293
05294 if (*wavestart < 1.0 && *waveend < 1.0) {
05295 firstLambda = line[0];
05296 lastLambda = line[nref-1];
05297 extrapolation = (lastLambda - firstLambda) / 10;
05298 firstLambda -= extrapolation;
05299 lastLambda += extrapolation;
05300 *wavestart = firstLambda;
05301 *waveend = lastLambda;
05302 }
05303 else {
05304 firstLambda = *wavestart;
05305 lastLambda = *waveend;
05306 }
05307
05308 nl = (lastLambda - firstLambda) / dispersion;
05309 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
05310 rdata = cpl_image_get_data_float(resampled);
05311
05312 if (calibration)
05313 idata = cpl_image_get_data_float(calibration);
05314
05315 if (residuals)
05316 ddata = cpl_image_get_data_float(residuals);
05317
05318 if (idscoeff)
05319 for (j = 0; j <= order; j++)
05320 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
05321
05322 if (restable) {
05323 cpl_table_set_size(restable, nref);
05324 cpl_table_new_column(restable, "wavelength", CPL_TYPE_DOUBLE);
05325 cpl_table_copy_data_double(restable, "wavelength", line);
05326 for (i = 0; i < ny; i += step) {
05327 snprintf(name, MAX_COLNAME, "r%d", i);
05328 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05329 snprintf(name, MAX_COLNAME, "d%d", i);
05330 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05331 snprintf(name, MAX_COLNAME, "p%d", i);
05332 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05333 }
05334 }
05335
05336
05337
05338
05339
05340
05341
05342 for (i = 0; i < ny; i++) {
05343 width = mos_lines_width(sdata + i*nx, nx);
05344 if (sradius > 0) {
05345 if (width > sradius) {
05346 uradius = width;
05347 }
05348 else {
05349 uradius = sradius;
05350 }
05351 }
05352 if (width < 5)
05353 width = 5;
05354 peaks = mos_peak_candidates(sdata + i*nx, nx, level, width);
05355 if (peaks) {
05356 peaks = mos_refine_peaks(sdata + i*nx, nx, peaks, width);
05357 }
05358 if (peaks) {
05359 output = mos_identify_peaks(peaks, lines, min_disp, max_disp, 0.05);
05360 if (output) {
05361 countLines = cpl_bivector_get_size(output);
05362 if (countLines < 4) {
05363 cpl_bivector_delete(output);
05364 cpl_vector_delete(peaks);
05365 if (nlines)
05366 nlines[i] = 0;
05367 if (error)
05368 error[i] = 0.0;
05369 continue;
05370 }
05371
05372
05373
05374
05375
05376 wavel = cpl_bivector_get_y(output);
05377 cpl_vector_subtract_scalar(wavel, refwave);
05378
05379 uorder = countLines / 2 - 1;
05380 if (uorder > order)
05381 uorder = order;
05382
05383
05384
05385
05386
05387
05388
05389
05390
05391
05392 ids = mos_poly_wav2pix(output, uorder, reject,
05393 2 * (uorder + 1), &usedLines,
05394 &ids_err);
05395
05396 if (ids == NULL) {
05397 cpl_bivector_delete(output);
05398 cpl_vector_delete(peaks);
05399 if (nlines)
05400 nlines[i] = 0;
05401 if (error)
05402 error[i] = 0.0;
05403 cpl_error_reset();
05404 continue;
05405 }
05406
05407 if (idscoeff) {
05408
05409
05410
05411
05412
05413
05414
05415 for (k = 0; k <= order; k++) {
05416 if (k > uorder) {
05417 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
05418 }
05419 else {
05420 cpl_table_set_double(idscoeff, clab[k], i,
05421 cpl_polynomial_get_coeff(ids, &k));
05422 }
05423 }
05424 }
05425
05426 if (sradius > 0) {
05427
05428
05429
05430
05431
05432 new_output = mos_find_peaks(sdata + i*nx, nx, lines,
05433 ids, refwave, uradius);
05434
05435 if (new_output) {
05436 cpl_bivector_delete(output);
05437 output = new_output;
05438 }
05439 else
05440 cpl_error_reset();
05441
05442
05443 cpl_polynomial_delete(ids);
05444
05445 countLines = cpl_bivector_get_size(output);
05446
05447 if (countLines < 4) {
05448 cpl_bivector_delete(output);
05449 cpl_vector_delete(peaks);
05450
05451
05452
05453
05454
05455
05456
05457 if (nlines)
05458 nlines[i] = 0;
05459 if (error)
05460 error[i] = 0.0;
05461 if (idscoeff)
05462 for (k = 0; k <= order; k++)
05463 cpl_table_set_invalid(idscoeff, clab[k], i);
05464 continue;
05465 }
05466
05467 wavel = cpl_bivector_get_y(output);
05468 cpl_vector_subtract_scalar(wavel, refwave);
05469
05470 uorder = countLines / 2 - 1;
05471 if (uorder > order)
05472 uorder = order;
05473
05474 ids = mos_poly_wav2pix(output, uorder, reject,
05475 2 * (uorder + 1), &usedLines,
05476 &ids_err);
05477
05478 if (ids == NULL) {
05479 cpl_bivector_delete(output);
05480 cpl_vector_delete(peaks);
05481
05482
05483
05484
05485
05486
05487
05488 if (nlines)
05489 nlines[i] = 0;
05490 if (error)
05491 error[i] = 0.0;
05492 if (idscoeff)
05493 for (k = 0; k <= order; k++)
05494 cpl_table_set_invalid(idscoeff, clab[k], i);
05495 cpl_error_reset();
05496 continue;
05497 }
05498
05499 if (idscoeff) {
05500 for (k = 0; k <= order; k++) {
05501 if (k > uorder) {
05502 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
05503 }
05504 else {
05505 cpl_table_set_double(idscoeff, clab[k], i,
05506 cpl_polynomial_get_coeff(ids, &k));
05507 }
05508 }
05509 }
05510
05511 }
05512
05513 if (nlines)
05514 nlines[i] = usedLines;
05515 if (error)
05516 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
05517
05518 pixstart = cpl_polynomial_eval_1d(ids,
05519 cpl_bivector_get_y_data(output)[0], NULL);
05520 pixend = cpl_polynomial_eval_1d(ids,
05521 cpl_bivector_get_y_data(output)[countLines-1], NULL);
05522 extrapolation = (pixend - pixstart) / 5;
05523 pixstart -= extrapolation;
05524 pixend += extrapolation;
05525 if (pixstart < 0)
05526 pixstart = 0;
05527 if (pixend > nx)
05528 pixend = nx;
05529
05530
05531
05532
05533
05534 if (calibration) {
05535 for (j = pixstart; j < pixend; j++) {
05536 (idata + i*nx)[j] = mos_eval_dds(ids, firstLambda,
05537 lastLambda, refwave,
05538 j);
05539 }
05540 }
05541
05542
05543
05544
05545
05546 for (j = 0; j < nl; j++) {
05547 lambda = firstLambda + j * dispersion;
05548 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
05549 NULL);
05550 pixel = fpixel;
05551 if (pixel >= 0 && pixel < nx-1) {
05552 v1 = (sdata + i*nx)[pixel];
05553 v2 = (sdata + i*nx)[pixel+1];
05554 vi = v1 + (v2-v1)*(fpixel-pixel);
05555 (rdata + i*nl)[j] = vi;
05556 }
05557 }
05558
05559
05560
05561
05562
05563 if (residuals || (restable && !(i%step))) {
05564 if (restable && !(i%step)) {
05565 lin = cpl_polynomial_new(1);
05566 for (k = 0; k < 2; k++)
05567 cpl_polynomial_set_coeff(lin, &k,
05568 cpl_polynomial_get_coeff(ids, &k));
05569 }
05570 for (j = 0; j < countLines; j++) {
05571 pixe = cpl_bivector_get_x_data(output)[j];
05572 wave = cpl_bivector_get_y_data(output)[j];
05573 value = pixe - cpl_polynomial_eval_1d(ids, wave, NULL);
05574 if (residuals) {
05575 pixel = pixe + 0.5;
05576 (ddata + i*nx)[pixel] = value;
05577 }
05578 if (restable && !(i%step)) {
05579 for (k = 0; k < nref; k++) {
05580 if (fabs(line[k] - refwave - wave) < 0.1) {
05581 snprintf(name, MAX_COLNAME, "r%d", i);
05582 cpl_table_set_double(restable, name,
05583 k, value);
05584 value = pixe
05585 - cpl_polynomial_eval_1d(lin, wave,
05586 NULL);
05587 snprintf(name, MAX_COLNAME, "d%d", i);
05588 cpl_table_set_double(restable, name,
05589 k, value);
05590 snprintf(name, MAX_COLNAME, "p%d", i);
05591 cpl_table_set_double(restable, name,
05592 k, pixe);
05593 break;
05594 }
05595 }
05596 }
05597 }
05598 if (restable && !(i%step)) {
05599 cpl_polynomial_delete(lin);
05600 }
05601 }
05602
05603
05604
05605
05606
05607 if (refmask) {
05608 mdata = cpl_mask_get_data(refmask);
05609 pixel = cpl_polynomial_eval_1d(ids, 0.0, NULL) + 0.5;
05610 if (pixel - 1 >= 0 && pixel + 1 < nx) {
05611 mdata[pixel-1 + i*nx] = CPL_BINARY_1;
05612 mdata[pixel + i*nx] = CPL_BINARY_1;
05613 mdata[pixel+1 + i*nx] = CPL_BINARY_1;
05614 }
05615 }
05616
05617 cpl_polynomial_delete(ids);
05618 cpl_bivector_delete(output);
05619 }
05620 cpl_vector_delete(peaks);
05621 }
05622 }
05623
05624 if (refmask) {
05625 kernel = cpl_matrix_new(3, 3);
05626 cpl_matrix_set(kernel, 0, 1, 1.0);
05627 cpl_matrix_set(kernel, 1, 1, 1.0);
05628 cpl_matrix_set(kernel, 2, 1, 1.0);
05629
05630 cpl_mask_dilation(refmask, kernel);
05631 cpl_mask_erosion(refmask, kernel);
05632 cpl_mask_erosion(refmask, kernel);
05633 cpl_mask_dilation(refmask, kernel);
05634
05635 cpl_matrix_delete(kernel);
05636
05637
05638
05639
05640
05641 mdata = cpl_mask_get_data(refmask);
05642 have_it = cpl_calloc(ny, sizeof(int));
05643
05644 for (i = 0; i < ny; i++, mdata += nx) {
05645 for (j = 0; j < nx; j++) {
05646 if (mdata[j] == CPL_BINARY_1) {
05647 have_it[i] = j;
05648 break;
05649 }
05650 }
05651 }
05652
05653 mdata = cpl_mask_get_data(refmask);
05654 in = 0;
05655 first = last = 0;
05656
05657 for (i = 0; i < ny; i++) {
05658 if (have_it[i]) {
05659 if (!in) {
05660 in = 1;
05661 if (first) {
05662 last = i;
05663 if (abs(have_it[first] - have_it[last]) < 3) {
05664 for (j = first; j < last; j++) {
05665 mdata[have_it[first] + nx*j + 0] = CPL_BINARY_1;
05666 mdata[have_it[first] + nx*j + 1] = CPL_BINARY_1;
05667 mdata[have_it[first] + nx*j + 2] = CPL_BINARY_1;
05668 }
05669 }
05670 }
05671 }
05672 }
05673 else {
05674 if (in) {
05675 in = 0;
05676 first = i - 1;
05677 }
05678 }
05679 }
05680
05681 cpl_free(have_it);
05682
05683 }
05684
05685
05686
05687
05688
05689
05690
05691
05692
05693
05694
05695 return resampled;
05696 }
05697
05698
05720
05721
05722
05723
05724
05725
05726
05727
05728
05729
05730
05731
05732
05733
05734
05735
05736
05737
05738
05739
05740
05741
05742
05743
05744
05745
05746
05747
05748
05749
05750
05751
05752
05753
05754
05755
05756
05757
05758
05759
05760
05761
05762
05763
05764
05765
05766
05767
05768
05769
05770
05771
05772
05773
05774
05775
05776
05777
05778
05779
05780
05781
05782
05783
05784
05785
05807 cpl_table *mos_locate_spectra(cpl_mask *mask)
05808 {
05809 const char *func = "mos_locate_spectra";
05810
05811 cpl_apertures *slits;
05812 cpl_image *labimage;
05813 cpl_image *refimage;
05814 cpl_table *slitpos;
05815 cpl_propertylist *sort_col;
05816 int nslits;
05817 int i;
05818
05819
05820 if (mask == NULL) {
05821 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05822 return NULL;
05823 }
05824
05825 labimage = cpl_image_labelise_mask_create(mask, &nslits);
05826
05827 if (nslits < 1) {
05828 cpl_image_delete(labimage);
05829 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05830 return NULL;
05831 }
05832
05833 refimage = cpl_image_new_from_mask(mask);
05834
05835 slits = cpl_apertures_new_from_image(refimage, labimage);
05836
05837 cpl_image_delete(labimage);
05838 cpl_image_delete(refimage);
05839
05840 nslits = cpl_apertures_get_size(slits);
05841 if (nslits < 1) {
05842 cpl_apertures_delete(slits);
05843 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05844 return NULL;
05845 }
05846
05847 slitpos = cpl_table_new(nslits);
05848 cpl_table_new_column(slitpos, "xtop", CPL_TYPE_DOUBLE);
05849 cpl_table_new_column(slitpos, "ytop", CPL_TYPE_DOUBLE);
05850 cpl_table_new_column(slitpos, "xbottom", CPL_TYPE_DOUBLE);
05851 cpl_table_new_column(slitpos, "ybottom", CPL_TYPE_DOUBLE);
05852 cpl_table_set_column_unit(slitpos, "xtop", "pixel");
05853 cpl_table_set_column_unit(slitpos, "ytop", "pixel");
05854 cpl_table_set_column_unit(slitpos, "xbottom", "pixel");
05855 cpl_table_set_column_unit(slitpos, "ybottom", "pixel");
05856
05857 for (i = 0; i < nslits; i++) {
05858 cpl_table_set_double(slitpos, "xtop", i,
05859 cpl_apertures_get_top_x(slits, i+1) - 1);
05860 cpl_table_set_double(slitpos, "ytop", i,
05861 cpl_apertures_get_top(slits, i+1));
05862 cpl_table_set_double(slitpos, "xbottom", i,
05863 cpl_apertures_get_bottom_x(slits, i+1) - 1);
05864 cpl_table_set_double(slitpos, "ybottom", i,
05865 cpl_apertures_get_bottom(slits, i+1));
05866 }
05867
05868 cpl_apertures_delete(slits);
05869
05870 sort_col = cpl_propertylist_new();
05871 cpl_propertylist_append_bool(sort_col, "ytop", 1);
05872 cpl_table_sort(slitpos, sort_col);
05873 cpl_propertylist_delete(sort_col);
05874
05875 return slitpos;
05876
05877 }
05878
05879
05895 cpl_error_code mos_validate_slits(cpl_table *slits)
05896 {
05897 const char *func = "mos_validate_slits";
05898
05899
05900 if (slits == NULL)
05901 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05902
05903 if (1 != cpl_table_has_column(slits, "xtop"))
05904 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05905
05906 if (1 != cpl_table_has_column(slits, "ytop"))
05907 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05908
05909 if (1 != cpl_table_has_column(slits, "xbottom"))
05910 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05911
05912 if (1 != cpl_table_has_column(slits, "ybottom"))
05913 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
05914
05915 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "xtop"))
05916 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05917
05918 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "ytop"))
05919 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05920
05921 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "xbottom"))
05922 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05923
05924 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "ybottom"))
05925 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
05926
05927 return CPL_ERROR_NONE;
05928 }
05929
05930
05959 cpl_error_code mos_rotate_slits(cpl_table *slits, int rotation, int nx, int ny)
05960 {
05961 const char *func = "mos_rotate_slits";
05962
05963 cpl_error_code error;
05964 char aux_name[] = "_0";
05965 int i;
05966
05967
05968 rotation %= 4;
05969 if (rotation < 0)
05970 rotation += 4;
05971
05972 if (rotation == 0)
05973 return CPL_ERROR_NONE;
05974
05975 error = mos_validate_slits(slits);
05976 if (error)
05977 return cpl_error_set(func, error);
05978
05979 if (rotation == 1 || rotation == 3) {
05980
05981
05982
05983
05984
05985 for (i = 0; i < 77; i++)
05986 if (1 == cpl_table_has_column(slits, aux_name))
05987 aux_name[1]++;
05988 if (1 == cpl_table_has_column(slits, aux_name))
05989 return cpl_error_set(func, CPL_ERROR_CONTINUE);
05990 cpl_table_name_column(slits, "xtop", aux_name);
05991 cpl_table_name_column(slits, "ytop", "xtop");
05992 cpl_table_name_column(slits, aux_name, "ytop");
05993 cpl_table_name_column(slits, "xbottom", aux_name);
05994 cpl_table_name_column(slits, "ybottom", "xbottom");
05995 cpl_table_name_column(slits, aux_name, "ybottom");
05996 }
05997
05998 if (rotation == 1 || rotation == 2) {
05999 cpl_table_multiply_scalar(slits, "xtop", -1.0);
06000 cpl_table_multiply_scalar(slits, "xbottom", -1.0);
06001 cpl_table_add_scalar(slits, "xtop", nx);
06002 cpl_table_add_scalar(slits, "xbottom", nx);
06003 }
06004
06005 if (rotation == 3 || rotation == 2) {
06006 cpl_table_multiply_scalar(slits, "ytop", -1.0);
06007 cpl_table_multiply_scalar(slits, "ybottom", -1.0);
06008 cpl_table_add_scalar(slits, "ytop", ny);
06009 cpl_table_add_scalar(slits, "ybottom", ny);
06010 }
06011
06012 return CPL_ERROR_NONE;
06013 }
06014
06015
06073 cpl_table *mos_identify_slits(cpl_table *slits, cpl_table *maskslits,
06074 cpl_table *global)
06075 {
06076 cpl_array *top_ident = NULL;;
06077 cpl_array *bot_ident = NULL;;
06078 cpl_matrix *mdata;
06079 cpl_matrix *mpattern;
06080 cpl_matrix *top_data;
06081 cpl_matrix *top_pattern;
06082 cpl_matrix *top_mdata;
06083 cpl_matrix *top_mpattern;
06084 cpl_matrix *bot_data;
06085 cpl_matrix *bot_pattern;
06086 cpl_matrix *bot_mdata;
06087 cpl_matrix *bot_mpattern;
06088 cpl_propertylist *sort_col;
06089 double *xtop;
06090 double *ytop;
06091 double *xmtop;
06092 double *ymtop;
06093 double *xbot;
06094 double *ybot;
06095 double *xmbot;
06096 double *ymbot;
06097 double top_scale, bot_scale;
06098 double angle, top_angle, bot_angle;
06099 double xmse, ymse;
06100 double xrms, top_xrms, bot_xrms;
06101 double yrms, top_yrms, bot_yrms;
06102 int nslits;
06103 int nmaskslits, use_pattern;
06104 int found_slits, found_slits_top, found_slits_bot;
06105 int degree;
06106 int i;
06107 cpl_table *positions;
06108 cpl_error_code error;
06109
06110 cpl_vector *point;
06111 double *dpoint;
06112 cpl_vector *xpos;
06113 cpl_vector *ypos;
06114 cpl_vector *xmpos;
06115 cpl_vector *ympos;
06116 cpl_bivector *mpos;
06117 cpl_polynomial *xpoly = NULL;
06118 cpl_polynomial *ypoly = NULL;
06119 cpl_polynomial *top_xpoly = NULL;
06120 cpl_polynomial *top_ypoly = NULL;
06121 cpl_polynomial *bot_xpoly = NULL;
06122 cpl_polynomial *bot_ypoly = NULL;
06123
06124 char *msg_multiplex = " ";
06125
06126
06127 error = mos_validate_slits(slits);
06128 if (error) {
06129 cpl_msg_error(cpl_func, "CCD slits table validation: %s",
06130 cpl_error_get_message());
06131 cpl_error_set(cpl_func, error);
06132 return NULL;
06133 }
06134
06135 error = mos_validate_slits(maskslits);
06136 if (error) {
06137 cpl_msg_error(cpl_func, "Mask slits table validation: %s",
06138 cpl_error_get_message());
06139 cpl_error_set(cpl_func, error);
06140 return NULL;
06141 }
06142
06143 if (1 != cpl_table_has_column(maskslits, "slit_id")) {
06144 cpl_msg_error(cpl_func, "Missing slits identifiers");
06145 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
06146 return NULL;
06147 }
06148
06149 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits, "slit_id")) {
06150 cpl_msg_error(cpl_func, "Wrong type used for slits identifiers");
06151 cpl_error_set(cpl_func, CPL_ERROR_INVALID_TYPE);
06152 return NULL;
06153 }
06154
06155 nslits = cpl_table_get_nrow(slits);
06156 nmaskslits = cpl_table_get_nrow(maskslits);
06157
06158 if (nslits == 0 || nmaskslits == 0) {
06159 cpl_msg_error(cpl_func, "Empty slits table");
06160 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
06161 return NULL;
06162 }
06163
06164 if (nslits > 25 && mos_multiplex < 0) {
06165 cpl_msg_info(cpl_func, "Many slits: using 'fast' pattern matching...");
06166 positions = mos_identify_slits_fast(slits, maskslits, global);
06167 if (positions == NULL)
06168 cpl_error_set_where(cpl_func);
06169 return positions;
06170 }
06171
06172
06173
06174
06175
06176 sort_col = cpl_propertylist_new();
06177 cpl_propertylist_append_bool(sort_col, "ytop", 1);
06178 cpl_table_sort(slits, sort_col);
06179 cpl_table_sort(maskslits, sort_col);
06180 cpl_propertylist_delete(sort_col);
06181
06182
06183
06184
06185
06186 if (nslits < 3 && nmaskslits > nslits) {
06187
06188
06189
06190
06191
06192
06193
06194
06195 if (nslits > 1)
06196 cpl_msg_warning(cpl_func, "Cannot match the %d found CCD slits "
06197 "with the %d mask slits: process will continue "
06198 "using the detected CCD slits positions", nslits,
06199 nmaskslits);
06200 else
06201 cpl_msg_warning(cpl_func, "Cannot match the found CCD slit with "
06202 "the %d mask slits: process will continue using "
06203 "the detected CCD slit position", nmaskslits);
06204 return NULL;
06205 }
06206
06207 if (nmaskslits < 3 && nslits > nmaskslits) {
06208
06209
06210
06211
06212
06213
06214
06215 cpl_msg_warning(cpl_func, "Cannot match the %d found CCD slits with "
06216 "the %d mask slits: process will continue using "
06217 "the detected CCD slits positions", nslits,
06218 nmaskslits);
06219 return NULL;
06220 }
06221
06222
06223
06224
06225
06226
06227
06228
06229 xtop = cpl_table_get_data_double(slits, "xtop");
06230 ytop = cpl_table_get_data_double(slits, "ytop");
06231 xmtop = cpl_table_get_data_double(maskslits, "xtop");
06232 ymtop = cpl_table_get_data_double(maskslits, "ytop");
06233
06234 xbot = cpl_table_get_data_double(slits, "xbottom");
06235 ybot = cpl_table_get_data_double(slits, "ybottom");
06236 xmbot = cpl_table_get_data_double(maskslits, "xbottom");
06237 ymbot = cpl_table_get_data_double(maskslits, "ybottom");
06238
06239 top_data = cpl_matrix_new(2, nslits);
06240 top_pattern = cpl_matrix_new(2, nmaskslits);
06241 bot_data = cpl_matrix_new(2, nslits);
06242 bot_pattern = cpl_matrix_new(2, nmaskslits);
06243
06244 for (i = 0; i < nslits; i++)
06245 cpl_matrix_set(top_data, 0, i, xtop[i]);
06246
06247 for (i = 0; i < nslits; i++)
06248 cpl_matrix_set(top_data, 1, i, ytop[i]);
06249
06250 for (i = 0; i < nmaskslits; i++)
06251 cpl_matrix_set(top_pattern, 0, i, xmtop[i]);
06252
06253 for (i = 0; i < nmaskslits; i++)
06254 cpl_matrix_set(top_pattern, 1, i, ymtop[i]);
06255
06256 for (i = 0; i < nslits; i++)
06257 cpl_matrix_set(bot_data, 0, i, xbot[i]);
06258
06259 for (i = 0; i < nslits; i++)
06260 cpl_matrix_set(bot_data, 1, i, ybot[i]);
06261
06262 for (i = 0; i < nmaskslits; i++)
06263 cpl_matrix_set(bot_pattern, 0, i, xmbot[i]);
06264
06265 for (i = 0; i < nmaskslits; i++)
06266 cpl_matrix_set(bot_pattern, 1, i, ymbot[i]);
06267
06268 if (nmaskslits > nslits)
06269 use_pattern = nslits;
06270 else
06271 use_pattern = nmaskslits;
06272
06273 top_ident = cpl_ppm_match_points(top_data, nslits, 1.0, top_pattern,
06274 use_pattern, 0.0, 0.1, 5, &top_mdata,
06275 &top_mpattern, &top_scale, &top_angle);
06276
06277 bot_ident = cpl_ppm_match_points(bot_data, nslits, 1.0, bot_pattern,
06278 use_pattern, 0.0, 0.1, 5, &bot_mdata,
06279 &bot_mpattern, &bot_scale, &bot_angle);
06280
06281 if (top_ident == NULL && bot_ident == NULL) {
06282 cpl_msg_warning(cpl_func, "Pattern matching failure: cannot match "
06283 "the %d found CCD slits with the %d mask slits: "
06284 "process will continue using the detected CCD "
06285 "slits positions", nslits, nmaskslits);
06286 return NULL;
06287 }
06288
06289 found_slits_top = 0;
06290 found_slits_bot = 0;
06291 if (top_ident && bot_ident) {
06292 cpl_msg_info(cpl_func, "Median platescale: %f +/- %f pixel/mm",
06293 (top_scale + bot_scale) / 2, fabs(top_scale - bot_scale));
06294 cpl_msg_info(cpl_func, "Median rotation: %f +/- %f degrees",
06295 (top_angle + bot_angle) / 2, fabs(top_angle - bot_angle));
06296 if (fabs(top_angle) < fabs(bot_angle))
06297 angle = fabs(top_angle);
06298 else
06299 angle = fabs(bot_angle);
06300 found_slits_top = cpl_matrix_get_ncol(top_mdata);
06301 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
06302 }
06303 else if (top_ident) {
06304 cpl_msg_info(cpl_func, "Median platescale: %f pixel/mm", top_scale);
06305 cpl_msg_info(cpl_func, "Median rotation: %f degrees", top_angle);
06306 angle = fabs(top_angle);
06307 found_slits_top = cpl_matrix_get_ncol(top_mdata);
06308 }
06309 else {
06310 cpl_msg_info(cpl_func, "Median platescale: %f pixel/mm", bot_scale);
06311 cpl_msg_info(cpl_func, "Median rotation: %f degrees", bot_angle);
06312 angle = fabs(bot_angle);
06313 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
06314 }
06315
06316 cpl_array_delete(top_ident);
06317 cpl_array_delete(bot_ident);
06318
06319 if (angle > 4.0) {
06320 cpl_msg_warning(cpl_func, "Uncertain pattern matching: the rotation "
06321 "angle is expected to be around zero. This match is "
06322 "rejected: the process will continue using the %d "
06323 "detected CCD slits positions", nslits);
06324 return NULL;
06325 }
06326
06327 found_slits = found_slits_top;
06328 if (found_slits < found_slits_bot)
06329 found_slits = found_slits_bot;
06330
06331 if (found_slits < 4) {
06332 cpl_msg_warning(cpl_func,
06333 "Too few safely identified slits: %d out of %d "
06334 "candidates (%d expected). Process will continue "
06335 "using the detected CCD slits positions", found_slits,
06336 nslits, nmaskslits);
06337 return NULL;
06338 }
06339
06340 cpl_msg_info(cpl_func, "Preliminary identified slits: %d out of %d "
06341 "candidates\n(%d expected)", found_slits, nslits,
06342 nmaskslits);
06343
06344 if (found_slits_top < 4)
06345 found_slits_top = 0;
06346
06347 if (found_slits_bot < 4)
06348 found_slits_bot = 0;
06349
06350
06351
06352
06353
06354
06355
06356 for (i = 0; i < 2; i++) {
06357 if (i) {
06358 found_slits = found_slits_top;
06359 mdata = top_mdata;
06360 mpattern = top_mpattern;
06361 }
06362 else {
06363 found_slits = found_slits_bot;
06364 mdata = bot_mdata;
06365 mpattern = bot_mpattern;
06366 }
06367
06368 if (found_slits == 0)
06369 continue;
06370 else if (found_slits < 10)
06371 degree = 1;
06372 else
06373 degree = 2;
06374
06375 xpos = cpl_vector_wrap(found_slits,
06376 cpl_matrix_get_data(mdata) );
06377 ypos = cpl_vector_wrap(found_slits,
06378 cpl_matrix_get_data(mdata) + found_slits);
06379 xmpos = cpl_vector_wrap(found_slits,
06380 cpl_matrix_get_data(mpattern) );
06381 ympos = cpl_vector_wrap(found_slits,
06382 cpl_matrix_get_data(mpattern) + found_slits);
06383 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
06384 xpoly = cpl_polynomial_fit_2d_create(mpos, xpos, degree, &xmse);
06385 ypoly = cpl_polynomial_fit_2d_create(mpos, ypos, degree, &ymse);
06386
06387 cpl_bivector_unwrap_vectors(mpos);
06388 cpl_vector_unwrap(xpos);
06389 cpl_vector_unwrap(ypos);
06390 cpl_vector_unwrap(xmpos);
06391 cpl_vector_unwrap(ympos);
06392 cpl_matrix_delete(mdata);
06393 cpl_matrix_delete(mpattern);
06394
06395 if (i) {
06396 top_xpoly = xpoly;
06397 top_ypoly = ypoly;
06398 top_xrms = sqrt(xmse*2*degree/(found_slits - 1));
06399 top_yrms = sqrt(ymse*2*degree/(found_slits - 1));
06400 }
06401 else {
06402 bot_xpoly = xpoly;
06403 bot_ypoly = ypoly;
06404 bot_xrms = sqrt(xmse*2*degree/(found_slits - 1));
06405 bot_yrms = sqrt(ymse*2*degree/(found_slits - 1));
06406 }
06407 }
06408
06409 if (top_xpoly && bot_xpoly) {
06410 if (top_xrms < bot_xrms) {
06411 xrms = top_xrms;
06412 xpoly = top_xpoly;
06413 cpl_polynomial_delete(bot_xpoly);
06414 }
06415 else {
06416 xrms = bot_xrms;
06417 xpoly = bot_xpoly;
06418 cpl_polynomial_delete(top_xpoly);
06419 }
06420 }
06421 else if (top_xpoly) {
06422 xrms = top_xrms;
06423 xpoly = top_xpoly;
06424 }
06425 else {
06426 xrms = bot_xrms;
06427 xpoly = bot_xpoly;
06428 }
06429
06430 if (top_ypoly && bot_ypoly) {
06431 if (top_yrms < bot_yrms) {
06432 yrms = top_yrms;
06433 ypoly = top_ypoly;
06434 cpl_polynomial_delete(bot_ypoly);
06435 }
06436 else {
06437 yrms = bot_yrms;
06438 ypoly = bot_ypoly;
06439 cpl_polynomial_delete(top_ypoly);
06440 }
06441 }
06442 else if (top_ypoly) {
06443 yrms = top_yrms;
06444 ypoly = top_ypoly;
06445 }
06446 else {
06447 yrms = bot_yrms;
06448 ypoly = bot_ypoly;
06449 }
06450
06451 if (xpoly == NULL || ypoly == NULL) {
06452 cpl_msg_warning(cpl_func, "Fit failure: the accuracy of the "
06453 "identified slits positions cannot be improved.");
06454 cpl_polynomial_delete(xpoly);
06455 cpl_polynomial_delete(ypoly);
06456 cpl_error_reset();
06457 return NULL;
06458 }
06459
06460 cpl_msg_info(cpl_func,
06461 "Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
06462 xrms, yrms);
06463
06464 if (global) {
06465 write_global_distortion(global, 0, xpoly);
06466 write_global_distortion(global, 7, ypoly);
06467 }
06468
06469
06470
06471
06472
06473
06474 positions = cpl_table_duplicate(maskslits);
06475 cpl_table_duplicate_column(positions, "xmtop", positions, "xtop");
06476 cpl_table_duplicate_column(positions, "ymtop", positions, "ytop");
06477 cpl_table_duplicate_column(positions, "xmbottom", positions, "xbottom");
06478 cpl_table_duplicate_column(positions, "ymbottom", positions, "ybottom");
06479
06480 point = cpl_vector_new(2);
06481 dpoint = cpl_vector_get_data(point);
06482
06483 for (i = 0; i < nmaskslits; i++) {
06484 double position;
06485
06486 dpoint[0] = cpl_table_get_double(positions, "xmtop", i, NULL);
06487 dpoint[1] = cpl_table_get_double(positions, "ymtop", i, NULL);
06488 position = cpl_polynomial_eval(xpoly, point);
06489
06490
06491
06492
06493
06494
06495 cpl_table_set_double(positions, "xtop", i, position);
06496 position = cpl_polynomial_eval(ypoly, point);
06497 cpl_table_set_double(positions, "ytop", i, position);
06498 dpoint[0] = cpl_table_get_double(positions, "xmbottom", i, NULL);
06499 dpoint[1] = cpl_table_get_double(positions, "ymbottom", i, NULL);
06500 position = cpl_polynomial_eval(xpoly, point);
06501 cpl_table_set_double(positions, "xbottom", i, position);
06502 position = cpl_polynomial_eval(ypoly, point);
06503 cpl_table_set_double(positions, "ybottom", i, position);
06504 }
06505
06506
06507
06508
06509
06510
06511
06512 cpl_vector_delete(point);
06513 cpl_polynomial_delete(xpoly);
06514 cpl_polynomial_delete(ypoly);
06515
06516 cpl_table_erase_column(positions, "xmtop");
06517 cpl_table_erase_column(positions, "ymtop");
06518 cpl_table_erase_column(positions, "xmbottom");
06519 cpl_table_erase_column(positions, "ymbottom");
06520
06521 if (mos_multiplex >= 0) {
06522 msg_multiplex =
06523 cpl_sprintf("in the CCD section between %d and %d pixel",
06524 mos_multiplex * mos_region_size,
06525 (mos_multiplex + 1) * mos_region_size);
06526 }
06527
06528 if (nmaskslits > nslits)
06529 cpl_msg_info(cpl_func,
06530 "Finally identified slits: %d out of %d expected %s\n"
06531 "(%d recovered)", nmaskslits, nmaskslits, msg_multiplex,
06532 nmaskslits - nslits);
06533 else if (nmaskslits < nslits)
06534 cpl_msg_info(cpl_func,
06535 "Finally identified slits: %d out of %d expected %s\n"
06536 "(%d rejected)", nmaskslits, nmaskslits, msg_multiplex,
06537 nslits - nmaskslits);
06538 else
06539 cpl_msg_info(cpl_func,
06540 "Finally identified slits: %d out of %d expected %s",
06541 nmaskslits, nmaskslits, msg_multiplex);
06542
06543 if (mos_multiplex >= 0) {
06544 cpl_free(msg_multiplex);
06545 }
06546
06547 return positions;
06548
06549 }
06550
06551
06552 cpl_table *mos_identify_slits_fast(cpl_table *slits, cpl_table *maskslits,
06553 cpl_table *global)
06554 {
06555 const char *func = "mos_identify_slits_fast";
06556
06557 cpl_propertylist *sort_col;
06558 cpl_table *positions;
06559 cpl_vector *scales;
06560 cpl_vector *angles;
06561 cpl_vector *point;
06562 cpl_vector *xpos;
06563 cpl_vector *ypos;
06564 cpl_vector *xmpos;
06565 cpl_vector *ympos;
06566 cpl_bivector *mpos;
06567 cpl_polynomial *xpoly = NULL;
06568 cpl_polynomial *ypoly = NULL;
06569 cpl_error_code error;
06570 int nslits;
06571 int nmaskslits;
06572 int found_slits;
06573 int i, j, k;
06574
06575 double dist1, dist2, dist3, dist, mindist;
06576 double scale, minscale, maxscale;
06577 double angle, minangle, maxangle;
06578 double *dscale;
06579 double *dangle;
06580 double *dpoint;
06581 double *xtop;
06582 double *ytop;
06583 double *xbottom;
06584 double *ybottom;
06585 double *xcenter;
06586 double *ycenter;
06587 double *xpseudo;
06588 double *ypseudo;
06589 int *slit_id;
06590 double *xmtop;
06591 double *ymtop;
06592 double *xmbottom;
06593 double *ymbottom;
06594 double *xmcenter;
06595 double *ymcenter;
06596 double *xmpseudo;
06597 double *ympseudo;
06598 double xmse, ymse;
06599 int *mslit_id;
06600 int *good;
06601 int minpos;
06602 int degree;
06603
06604 double sradius = 0.01;
06605 int in_sradius;
06606
06607 double pi = 3.14159265358979323846;
06608
06609
06610 error = mos_validate_slits(slits);
06611 if (error) {
06612 cpl_msg_error(func, "CCD slits table validation: %s",
06613 cpl_error_get_message());
06614 cpl_error_set(func, error);
06615 return NULL;
06616 }
06617
06618 error = mos_validate_slits(maskslits);
06619 if (error) {
06620 cpl_msg_error(func, "Mask slits table validation: %s",
06621 cpl_error_get_message());
06622 cpl_error_set(func, error);
06623 return NULL;
06624 }
06625
06626 if (1 != cpl_table_has_column(maskslits, "slit_id")) {
06627 cpl_msg_error(func, "Missing slits identifiers");
06628 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
06629 return NULL;
06630 }
06631
06632 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits, "slit_id")) {
06633 cpl_msg_error(func, "Wrong type used for slits identifiers");
06634 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
06635 return NULL;
06636 }
06637
06638 nslits = cpl_table_get_nrow(slits);
06639 nmaskslits = cpl_table_get_nrow(maskslits);
06640
06641 if (nslits == 0 || nmaskslits == 0) {
06642 cpl_msg_error(func, "Empty slits table");
06643 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
06644 return NULL;
06645 }
06646
06647
06648
06649
06650
06651
06652
06653 if (cpl_table_has_column(slits, "xcenter"))
06654 cpl_table_erase_column(slits, "xcenter");
06655
06656 if (cpl_table_has_column(slits, "ycenter"))
06657 cpl_table_erase_column(slits, "ycenter");
06658
06659 if (cpl_table_has_column(maskslits, "xcenter"))
06660 cpl_table_erase_column(maskslits, "xcenter");
06661
06662 if (cpl_table_has_column(maskslits, "ycenter"))
06663 cpl_table_erase_column(maskslits, "ycenter");
06664
06665 cpl_table_duplicate_column(slits, "xcenter", slits, "xtop");
06666 cpl_table_add_columns(slits, "xcenter", "xbottom");
06667 cpl_table_divide_scalar(slits, "xcenter", 2.0);
06668 cpl_table_duplicate_column(slits, "ycenter", slits, "ytop");
06669 cpl_table_add_columns(slits, "ycenter", "ybottom");
06670 cpl_table_divide_scalar(slits, "ycenter", 2.0);
06671
06672 cpl_table_duplicate_column(maskslits, "xcenter", maskslits, "xtop");
06673 cpl_table_add_columns(maskslits, "xcenter", "xbottom");
06674 cpl_table_divide_scalar(maskslits, "xcenter", 2.0);
06675 cpl_table_duplicate_column(maskslits, "ycenter", maskslits, "ytop");
06676 cpl_table_add_columns(maskslits, "ycenter", "ybottom");
06677 cpl_table_divide_scalar(maskslits, "ycenter", 2.0);
06678
06679
06680
06681
06682
06683
06684 sort_col = cpl_propertylist_new();
06685 cpl_propertylist_append_bool(sort_col, "ycenter", 1);
06686 cpl_table_sort(slits, sort_col);
06687 cpl_table_sort(maskslits, sort_col);
06688 cpl_propertylist_delete(sort_col);
06689
06690
06691
06692
06693
06694
06695 if (nslits < 3 && nmaskslits > nslits) {
06696
06697
06698
06699
06700
06701
06702
06703
06704 if (nslits > 1)
06705 cpl_msg_warning(func, "Cannot match the found CCD slit with the "
06706 "%d mask slits: process will continue using the "
06707 "detected CCD slit position", nmaskslits);
06708 else
06709 cpl_msg_warning(func, "Cannot match the %d found CCD slits with "
06710 "the %d mask slits: process will continue using "
06711 "the detected CCD slits positions", nslits,
06712 nmaskslits);
06713 return NULL;
06714 }
06715
06716 if (nslits <= 3 && nslits == nmaskslits) {
06717
06718 cpl_msg_warning(func, "Too few slits (%d) on mask and CCD", nslits);
06719 cpl_msg_warning(func, "Their detected positions are left unchanged");
06720
06721
06722
06723
06724
06725
06726
06727
06728
06729
06730 positions = cpl_table_duplicate(slits);
06731 cpl_table_erase_column(slits, "xcenter");
06732 cpl_table_erase_column(slits, "ycenter");
06733 cpl_table_duplicate_column(positions, "xmtop", maskslits, "xtop");
06734 cpl_table_duplicate_column(positions, "ymtop", maskslits, "ytop");
06735 cpl_table_duplicate_column(positions, "xmbottom", maskslits, "xbottom");
06736 cpl_table_duplicate_column(positions, "ymbottom", maskslits, "ybottom");
06737 cpl_table_duplicate_column(positions, "xmcenter", maskslits, "xcenter");
06738 cpl_table_duplicate_column(positions, "ymcenter", maskslits, "ycenter");
06739 cpl_table_duplicate_column(positions, "slit_id", maskslits, "slit_id");
06740 cpl_table_erase_column(maskslits, "xcenter");
06741 cpl_table_erase_column(maskslits, "ycenter");
06742
06743 if (nslits > 1) {
06744 xcenter = cpl_table_get_data_double(positions, "xcenter");
06745 ycenter = cpl_table_get_data_double(positions, "ycenter");
06746 xmcenter = cpl_table_get_data_double(positions, "xmcenter");
06747 ymcenter = cpl_table_get_data_double(positions, "ymcenter");
06748
06749 dist1 = (xcenter[0] - xcenter[1])*(xcenter[0] - xcenter[1])
06750 + (ycenter[0] - ycenter[1])*(ycenter[0] - ycenter[1]);
06751 dist2 = (xmcenter[0] - xmcenter[1])*(xmcenter[0] - xmcenter[1])
06752 + (ymcenter[0] - ymcenter[1])*(ymcenter[0] - ymcenter[1]);
06753 scale = sqrt(dist1/dist2);
06754
06755 if (nslits == 3) {
06756 dist1 = (xcenter[1] - xcenter[2])*(xcenter[1] - xcenter[2])
06757 + (ycenter[1] - ycenter[2])*(ycenter[1] - ycenter[2]);
06758 dist2 = (xmcenter[1] - xmcenter[2])*(xmcenter[1] - xmcenter[2])
06759 + (ymcenter[1] - ymcenter[2])*(ymcenter[1] - ymcenter[2]);
06760 scale += sqrt(dist1/dist2);
06761 scale /= 2;
06762 }
06763
06764 cpl_msg_info(func, "Platescale: %f pixel/mm", scale);
06765 }
06766
06767 return positions;
06768 }
06769
06770 if (nmaskslits < 3 && nslits > nmaskslits) {
06771
06772
06773
06774
06775
06776
06777
06778 cpl_msg_warning(func, "Cannot match the %d found CCD slits with "
06779 "the %d mask slits: process will continue using "
06780 "the detected CCD slits positions", nslits,
06781 nmaskslits);
06782 return NULL;
06783 }
06784
06785
06786
06787
06788
06789
06790
06791
06792
06793
06794
06795
06796
06797
06798
06799
06800
06801
06802
06803
06804
06805
06806
06807
06808
06809
06810
06811
06812 if (cpl_table_has_column(slits, "xpseudo"))
06813 cpl_table_erase_column(slits, "xpseudo");
06814
06815 if (cpl_table_has_column(slits, "ypseudo"))
06816 cpl_table_erase_column(slits, "ypseudo");
06817
06818 if (cpl_table_has_column(maskslits, "xpseudo"))
06819 cpl_table_erase_column(maskslits, "xpseudo");
06820
06821 if (cpl_table_has_column(maskslits, "ypseudo"))
06822 cpl_table_erase_column(maskslits, "ypseudo");
06823
06824 cpl_table_duplicate_column(slits, "xpseudo", slits, "xcenter");
06825 cpl_table_duplicate_column(slits, "ypseudo", slits, "ycenter");
06826
06827 xcenter = cpl_table_get_data_double(slits, "xcenter");
06828 ycenter = cpl_table_get_data_double(slits, "ycenter");
06829 xpseudo = cpl_table_get_data_double(slits, "xpseudo");
06830 ypseudo = cpl_table_get_data_double(slits, "ypseudo");
06831
06832 for (i = 1; i < nslits - 1; i++) {
06833 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
06834 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
06835 dist2 = (xcenter[i-1] - xcenter[i+1]) * (xcenter[i-1] - xcenter[i+1])
06836 + (ycenter[i-1] - ycenter[i+1]) * (ycenter[i-1] - ycenter[i+1]);
06837 dist3 = (xcenter[i] - xcenter[i+1]) * (xcenter[i] - xcenter[i+1])
06838 + (ycenter[i] - ycenter[i+1]) * (ycenter[i] - ycenter[i+1]);
06839 xpseudo[i] = sqrt(dist1/dist2);
06840 ypseudo[i] = sqrt(dist3/dist2);
06841 }
06842
06843 cpl_table_set_invalid(slits, "xpseudo", 0);
06844 cpl_table_set_invalid(slits, "xpseudo", nslits-1);
06845 cpl_table_set_invalid(slits, "ypseudo", 0);
06846 cpl_table_set_invalid(slits, "ypseudo", nslits-1);
06847
06848 cpl_table_duplicate_column(maskslits, "xpseudo", maskslits, "xcenter");
06849 cpl_table_duplicate_column(maskslits, "ypseudo", maskslits, "ycenter");
06850
06851 xcenter = cpl_table_get_data_double(maskslits, "xcenter");
06852 ycenter = cpl_table_get_data_double(maskslits, "ycenter");
06853 xmpseudo = cpl_table_get_data_double(maskslits, "xpseudo");
06854 ympseudo = cpl_table_get_data_double(maskslits, "ypseudo");
06855
06856 for (i = 1; i < nmaskslits - 1; i++) {
06857 dist1 = (xcenter[i-1] - xcenter[i])*(xcenter[i-1] - xcenter[i])
06858 + (ycenter[i-1] - ycenter[i])*(ycenter[i-1] - ycenter[i]);
06859 dist2 = (xcenter[i-1] - xcenter[i+1])*(xcenter[i-1] - xcenter[i+1])
06860 + (ycenter[i-1] - ycenter[i+1])*(ycenter[i-1] - ycenter[i+1]);
06861 dist3 = (xcenter[i] - xcenter[i+1])*(xcenter[i] - xcenter[i+1])
06862 + (ycenter[i] - ycenter[i+1])*(ycenter[i] - ycenter[i+1]);
06863 xmpseudo[i] = sqrt(dist1/dist2);
06864 ympseudo[i] = sqrt(dist3/dist2);
06865 }
06866
06867 cpl_table_set_invalid(maskslits, "xpseudo", 0);
06868 cpl_table_set_invalid(maskslits, "xpseudo", nmaskslits-1);
06869 cpl_table_set_invalid(maskslits, "ypseudo", 0);
06870 cpl_table_set_invalid(maskslits, "ypseudo", nmaskslits-1);
06871
06872
06873
06874
06875
06876
06877
06878
06879
06880
06881
06882 if (cpl_table_has_column(slits, "slit_id"))
06883 cpl_table_erase_column(slits, "slit_id");
06884 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
06885 slit_id = cpl_table_get_data_int(maskslits, "slit_id");
06886
06887 for (i = 1; i < nmaskslits - 1; i++) {
06888 in_sradius = 0;
06889 mindist = (xmpseudo[i] - xpseudo[1]) * (xmpseudo[i] - xpseudo[1])
06890 + (ympseudo[i] - ypseudo[1]) * (ympseudo[i] - ypseudo[1]);
06891 minpos = 1;
06892 if (mindist < sradius*sradius)
06893 in_sradius++;
06894 for (j = 2; j < nslits - 1; j++) {
06895 dist = (xmpseudo[i] - xpseudo[j]) * (xmpseudo[i] - xpseudo[j])
06896 + (ympseudo[i] - ypseudo[j]) * (ympseudo[i] - ypseudo[j]);
06897 if (dist < sradius*sradius)
06898 in_sradius++;
06899 if (in_sradius > 1)
06900 break;
06901 if (mindist > dist) {
06902 mindist = dist;
06903 minpos = j;
06904 }
06905 }
06906
06907 mindist = sqrt(mindist);
06908
06909 if (mindist < sradius && in_sradius == 1) {
06910 cpl_table_set_int(slits, "slit_id", minpos-1, slit_id[i-1]);
06911 cpl_table_set_int(slits, "slit_id", minpos, slit_id[i]);
06912 cpl_table_set_int(slits, "slit_id", minpos+1, slit_id[i+1]);
06913 }
06914 }
06915
06916
06917
06918
06919
06920
06921
06922 found_slits = nslits - cpl_table_count_invalid(slits, "slit_id");
06923
06924 if (found_slits < 3) {
06925 cpl_msg_warning(func, "Too few preliminarily identified slits: "
06926 "%d out of %d", found_slits, nslits);
06927 if (nslits == nmaskslits) {
06928 cpl_msg_warning(func, "(this is not an error, it could be caused "
06929 "by a mask with regularly located slits)");
06930 cpl_msg_warning(func, "The detected slits positions are left "
06931 "unchanged");
06932
06933
06934
06935
06936
06937
06938
06939
06940 cpl_table_erase_column(slits, "slit_id");
06941 cpl_table_erase_column(slits, "xpseudo");
06942 cpl_table_erase_column(slits, "ypseudo");
06943 positions = cpl_table_duplicate(slits);
06944 cpl_table_erase_column(slits, "xcenter");
06945 cpl_table_erase_column(slits, "ycenter");
06946
06947 cpl_table_erase_column(maskslits, "xpseudo");
06948 cpl_table_erase_column(maskslits, "ypseudo");
06949 cpl_table_duplicate_column(positions, "xmtop",
06950 maskslits, "xtop");
06951 cpl_table_duplicate_column(positions, "ymtop",
06952 maskslits, "ytop");
06953 cpl_table_duplicate_column(positions, "xmbottom",
06954 maskslits, "xbottom");
06955 cpl_table_duplicate_column(positions, "ymbottom",
06956 maskslits, "ybottom");
06957 cpl_table_duplicate_column(positions, "xmcenter",
06958 maskslits, "xcenter");
06959 cpl_table_duplicate_column(positions, "ymcenter",
06960 maskslits, "ycenter");
06961 cpl_table_duplicate_column(positions, "slit_id",
06962 maskslits, "slit_id");
06963 cpl_table_erase_column(maskslits, "xcenter");
06964 cpl_table_erase_column(maskslits, "ycenter");
06965 return positions;
06966 }
06967 else {
06968 cpl_table_erase_column(slits, "slit_id");
06969 cpl_table_erase_column(slits, "xpseudo");
06970 cpl_table_erase_column(slits, "ypseudo");
06971 positions = cpl_table_duplicate(slits);
06972 cpl_table_erase_column(slits, "xcenter");
06973 cpl_table_erase_column(slits, "ycenter");
06974 cpl_msg_warning(func, "(the failure could be caused "
06975 "by a mask with regularly located slits)");
06976 return NULL;
06977 }
06978 }
06979 else {
06980 cpl_msg_info(func, "Preliminarily identified slits: %d out of %d "
06981 "candidates (%d expected)", found_slits, nslits,
06982 nmaskslits);
06983 }
06984
06985
06986
06987
06988
06989
06990
06991
06992 positions = cpl_table_new(found_slits);
06993 cpl_table_new_column(positions, "slit_id", CPL_TYPE_INT);
06994 cpl_table_new_column(positions, "xtop", CPL_TYPE_DOUBLE);
06995 cpl_table_new_column(positions, "ytop", CPL_TYPE_DOUBLE);
06996 cpl_table_new_column(positions, "xbottom", CPL_TYPE_DOUBLE);
06997 cpl_table_new_column(positions, "ybottom", CPL_TYPE_DOUBLE);
06998 cpl_table_new_column(positions, "xcenter", CPL_TYPE_DOUBLE);
06999 cpl_table_new_column(positions, "ycenter", CPL_TYPE_DOUBLE);
07000 cpl_table_new_column(positions, "xmtop", CPL_TYPE_DOUBLE);
07001 cpl_table_new_column(positions, "ymtop", CPL_TYPE_DOUBLE);
07002 cpl_table_new_column(positions, "xmbottom", CPL_TYPE_DOUBLE);
07003 cpl_table_new_column(positions, "ymbottom", CPL_TYPE_DOUBLE);
07004 cpl_table_new_column(positions, "xmcenter", CPL_TYPE_DOUBLE);
07005 cpl_table_new_column(positions, "ymcenter", CPL_TYPE_DOUBLE);
07006 cpl_table_new_column(positions, "good", CPL_TYPE_INT);
07007 cpl_table_fill_column_window_int(positions, "good", 0, found_slits, 0);
07008
07009 slit_id = cpl_table_get_data_int (slits, "slit_id");
07010 xtop = cpl_table_get_data_double(slits, "xtop");
07011 ytop = cpl_table_get_data_double(slits, "ytop");
07012 xbottom = cpl_table_get_data_double(slits, "xbottom");
07013 ybottom = cpl_table_get_data_double(slits, "ybottom");
07014 xcenter = cpl_table_get_data_double(slits, "xcenter");
07015 ycenter = cpl_table_get_data_double(slits, "ycenter");
07016
07017 mslit_id = cpl_table_get_data_int (maskslits, "slit_id");
07018 xmtop = cpl_table_get_data_double(maskslits, "xtop");
07019 ymtop = cpl_table_get_data_double(maskslits, "ytop");
07020 xmbottom = cpl_table_get_data_double(maskslits, "xbottom");
07021 ymbottom = cpl_table_get_data_double(maskslits, "ybottom");
07022 xmcenter = cpl_table_get_data_double(maskslits, "xcenter");
07023 ymcenter = cpl_table_get_data_double(maskslits, "ycenter");
07024
07025
07026
07027
07028
07029
07030
07031
07032 k = 0;
07033 cpl_table_fill_invalid_int(slits, "slit_id", 0);
07034 for (i = 0; i < nmaskslits; i++) {
07035 for (j = 0; j < nslits; j++) {
07036 if (slit_id[j] == 0)
07037 continue;
07038 if (mslit_id[i] == slit_id[j]) {
07039 cpl_table_set_int (positions, "slit_id", k, slit_id[j]);
07040
07041 cpl_table_set_double(positions, "xtop", k, xtop[j]);
07042 cpl_table_set_double(positions, "ytop", k, ytop[j]);
07043 cpl_table_set_double(positions, "xbottom", k, xbottom[j]);
07044 cpl_table_set_double(positions, "ybottom", k, ybottom[j]);
07045 cpl_table_set_double(positions, "xcenter", k, xcenter[j]);
07046 cpl_table_set_double(positions, "ycenter", k, ycenter[j]);
07047
07048 cpl_table_set_double(positions, "xmtop", k, xmtop[i]);
07049 cpl_table_set_double(positions, "ymtop", k, ymtop[i]);
07050 cpl_table_set_double(positions, "xmbottom", k, xmbottom[i]);
07051 cpl_table_set_double(positions, "ymbottom", k, ymbottom[i]);
07052 cpl_table_set_double(positions, "xmcenter", k, xmcenter[i]);
07053 cpl_table_set_double(positions, "ymcenter", k, ymcenter[i]);
07054
07055 k++;
07056
07057 break;
07058 }
07059 }
07060 }
07061
07062 found_slits = k;
07063
07064 cpl_table_erase_column(slits, "slit_id");
07065 cpl_table_erase_column(slits, "xpseudo");
07066 cpl_table_erase_column(slits, "ypseudo");
07067 cpl_table_erase_column(slits, "xcenter");
07068 cpl_table_erase_column(slits, "ycenter");
07069 cpl_table_erase_column(maskslits, "xpseudo");
07070 cpl_table_erase_column(maskslits, "ypseudo");
07071 cpl_table_erase_column(maskslits, "xcenter");
07072 cpl_table_erase_column(maskslits, "ycenter");
07073
07074
07075
07076
07077
07078
07079
07080
07081
07082 ytop = cpl_table_get_data_double(positions, "ytop");
07083 ybottom = cpl_table_get_data_double(positions, "ybottom");
07084 xcenter = cpl_table_get_data_double(positions, "xcenter");
07085 ycenter = cpl_table_get_data_double(positions, "ycenter");
07086 xmcenter = cpl_table_get_data_double(positions, "xmcenter");
07087 ymcenter = cpl_table_get_data_double(positions, "ymcenter");
07088
07089 scales = cpl_vector_new(found_slits - 1);
07090 dscale = cpl_vector_get_data(scales);
07091 angles = cpl_vector_new(found_slits - 1);
07092 dangle = cpl_vector_get_data(angles);
07093
07094 for (i = 1; i < found_slits; i++) {
07095 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
07096 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
07097 dist2 = (xmcenter[i-1] - xmcenter[i]) * (xmcenter[i-1] - xmcenter[i])
07098 + (ymcenter[i-1] - ymcenter[i]) * (ymcenter[i-1] - ymcenter[i]);
07099 dscale[i-1] = sqrt(dist1/dist2);
07100 dangle[i-1] = atan2(ycenter[i-1] - ycenter[i],
07101 xcenter[i-1] - xcenter[i])
07102 - atan2(ymcenter[i-1] - ymcenter[i],
07103 xmcenter[i-1] - xmcenter[i]);
07104 dangle[i-1] *= 180;
07105 dangle[i-1] /= pi;
07106 }
07107
07108 minscale = cpl_vector_get_min(scales);
07109 scale = cpl_vector_get_median_const(scales);
07110 maxscale = cpl_vector_get_max(scales);
07111
07112 minangle = cpl_vector_get_min(angles);
07113 angle = cpl_vector_get_median_const(angles);
07114 maxangle = cpl_vector_get_max(angles);
07115
07116 cpl_msg_info(func, "Median platescale: %f pixel/mm", scale);
07117 cpl_msg_info(func, "Minmax platescale: %f, %f pixel/mm",
07118 minscale, maxscale);
07119
07120 cpl_msg_info(func, "Median rotation: %f degrees", angle);
07121 cpl_msg_info(func, "Minmax rotation: %f, %f degrees",
07122 minangle, maxangle);
07123
07124 good = cpl_table_get_data_int(positions, "good");
07125
07126 good[0] = good[found_slits - 1] = 1;
07127 for (i = 1; i < found_slits; i++) {
07128 if (fabs((dscale[i-1] - scale)/scale) < 0.10
07129 && fabs(dangle[i-1] - angle) < 2) {
07130 good[i-1]++;
07131 good[i]++;
07132 }
07133 }
07134
07135 for (i = 0; i < found_slits; i++) {
07136 if (good[i] < 2)
07137 good[i] = 0;
07138 else
07139 good[i] = 1;
07140 }
07141
07142
07143
07144
07145
07146
07147
07148
07149
07150
07151
07152
07153
07154
07155
07156
07157
07158
07159
07160
07161
07162
07163
07164
07165
07166
07167
07168
07169
07170
07171
07172
07173
07174
07175 cpl_vector_delete(scales);
07176 cpl_vector_delete(angles);
07177
07178 cpl_table_and_selected_int(positions, "good", CPL_EQUAL_TO, 0);
07179 cpl_table_erase_selected(positions);
07180 cpl_table_erase_column(positions, "good");
07181 found_slits = cpl_table_get_nrow(positions);
07182
07183 if (found_slits < 4) {
07184
07185
07186
07187
07188
07189
07190
07191 cpl_msg_warning(func, "Too few safely identified slits: %d out of %d "
07192 "candidates (%d expected). Process will continue "
07193 "using the detected CCD slits positions", found_slits,
07194 nslits, nmaskslits);
07195 cpl_table_delete(positions);
07196 return NULL;
07197 }
07198 else {
07199 cpl_msg_info(func, "Safely identified slits: %d out of %d "
07200 "candidates\n(%d expected)", found_slits, nslits,
07201 nmaskslits);
07202 }
07203
07204
07205
07206
07207
07208
07209
07210
07211 xpos = cpl_vector_wrap(found_slits,
07212 cpl_table_get_data_double(positions, "xcenter"));
07213 ypos = cpl_vector_wrap(found_slits,
07214 cpl_table_get_data_double(positions, "ycenter"));
07215 xmpos = cpl_vector_wrap(found_slits,
07216 cpl_table_get_data_double(positions, "xmcenter"));
07217 ympos = cpl_vector_wrap(found_slits,
07218 cpl_table_get_data_double(positions, "ymcenter"));
07219 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
07220
07221 if (found_slits < 10)
07222 degree = 1;
07223 else
07224 degree = 2;
07225
07226 xpoly = cpl_polynomial_fit_2d_create(mpos, xpos, degree, &xmse);
07227 if (xpoly != NULL)
07228 ypoly = cpl_polynomial_fit_2d_create(mpos, ypos, degree, &ymse);
07229 cpl_bivector_unwrap_vectors(mpos);
07230 cpl_vector_unwrap(xpos);
07231 cpl_vector_unwrap(ypos);
07232 cpl_vector_unwrap(xmpos);
07233 cpl_vector_unwrap(ympos);
07234 if (ypoly == NULL) {
07235 if (found_slits == nmaskslits) {
07236 cpl_msg_warning(func, "Fit failure: the accuracy of the "
07237 "identified slits positions is not improved.");
07238
07239
07240
07241
07242
07243
07244
07245
07246
07247 } else {
07248 cpl_msg_info(func, "Fit failure: not all slits have been "
07249 "identified. Process will continue using "
07250 "the detected CCD slits positions");
07251 }
07252
07253 cpl_polynomial_delete(xpoly);
07254 return positions;
07255 }
07256
07257 cpl_msg_info(func, "Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
07258 sqrt(xmse), sqrt(ymse));
07259
07260 if (global) {
07261 write_global_distortion(global, 0, xpoly);
07262 write_global_distortion(global, 7, ypoly);
07263 }
07264
07265
07266
07267
07268
07269
07270 cpl_table_delete(positions);
07271
07272 positions = cpl_table_duplicate(maskslits);
07273 cpl_table_duplicate_column(positions, "xmtop", positions, "xtop");
07274 cpl_table_duplicate_column(positions, "ymtop", positions, "ytop");
07275 cpl_table_duplicate_column(positions, "xmbottom", positions, "xbottom");
07276 cpl_table_duplicate_column(positions, "ymbottom", positions, "ybottom");
07277
07278 point = cpl_vector_new(2);
07279 dpoint = cpl_vector_get_data(point);
07280
07281 for (i = 0; i < nmaskslits; i++) {
07282 dpoint[0] = cpl_table_get_double(positions, "xmtop", i, NULL);
07283 dpoint[1] = cpl_table_get_double(positions, "ymtop", i, NULL);
07284 cpl_table_set_double(positions, "xtop", i,
07285 cpl_polynomial_eval(xpoly, point));
07286 cpl_table_set_double(positions, "ytop", i,
07287 cpl_polynomial_eval(ypoly, point));
07288 dpoint[0] = cpl_table_get_double(positions, "xmbottom", i, NULL);
07289 dpoint[1] = cpl_table_get_double(positions, "ymbottom", i, NULL);
07290 cpl_table_set_double(positions, "xbottom", i,
07291 cpl_polynomial_eval(xpoly, point));
07292 cpl_table_set_double(positions, "ybottom", i,
07293 cpl_polynomial_eval(ypoly, point));
07294 }
07295
07296 cpl_vector_delete(point);
07297 cpl_polynomial_delete(xpoly);
07298 cpl_polynomial_delete(ypoly);
07299
07300 cpl_table_erase_column(positions, "xmtop");
07301 cpl_table_erase_column(positions, "ymtop");
07302 cpl_table_erase_column(positions, "xmbottom");
07303 cpl_table_erase_column(positions, "ymbottom");
07304
07305 if (nmaskslits > nslits)
07306 cpl_msg_info(func, "Finally identified slits: %d out of %d expected\n"
07307 "(%d recovered)", nmaskslits, nmaskslits, nmaskslits - nslits);
07308 else if (nmaskslits < nslits)
07309 cpl_msg_info(func, "Finally identified slits: %d out of %d expected\n"
07310 "(%d rejected)", nmaskslits, nmaskslits, nslits - nmaskslits);
07311 else
07312 cpl_msg_info(func, "Finally identified slits: %d out of %d expected",
07313 nmaskslits, nmaskslits);
07314
07315 return positions;
07316 }
07317
07318
07360 cpl_table *mos_trace_flat(cpl_image *flat, cpl_table *slits, double reference,
07361 double blue, double red, double dispersion)
07362 {
07363
07364 const char *func = "mos_trace_flat";
07365
07366 cpl_image *gradient;
07367 cpl_image *sgradient;
07368 float *dgradient;
07369 float level = 500;
07370 cpl_vector *row;
07371 cpl_vector *srow;
07372 cpl_vector **peaks;
07373 double *peak;
07374 int *slit_id;
07375 float *g;
07376 double *r;
07377 double *xtop;
07378 double *ytop;
07379 double *xbottom;
07380 double *ybottom;
07381 double min, dist;
07382 double sradius;
07383 double tolerance;
07384 double start_y, prev_y;
07385 int minpos;
07386 int nslits;
07387 int nrows;
07388 int step = 10;
07389 int filtbox = 15;
07390 int nx, ny, npix;
07391 int pos, ypos;
07392 int npeaks;
07393 int pixel_above, pixel_below;
07394 int i, j, k, l;
07395 char trace_id[MAX_COLNAME];
07396
07397 cpl_table *traces;
07398
07399
07400 if (flat == NULL || slits == NULL) {
07401 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07402 return NULL;
07403 }
07404
07405 if (dispersion <= 0.0) {
07406 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07407 return NULL;
07408 }
07409
07410 if (red - blue < dispersion) {
07411 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07412 return NULL;
07413 }
07414
07415
07416
07417
07418
07419
07420 nslits = cpl_table_get_nrow(slits);
07421 if (1 != cpl_table_has_column(slits, "slit_id")) {
07422 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
07423 for (i = 0; i < nslits; i++)
07424 cpl_table_set_int(slits, "slit_id", i, -(i+1));
07425 }
07426
07427 slit_id = cpl_table_get_data_int(slits, "slit_id");
07428
07429 nx = cpl_image_get_size_x(flat);
07430 ny = cpl_image_get_size_y(flat);
07431 npix = nx * ny;
07432
07433 gradient = cpl_image_duplicate(flat);
07434 dgradient = cpl_image_get_data_float(gradient);
07435
07436 for (i = 0; i < ny - 1; i++) {
07437 k = i * nx;
07438 for (j = 0; j < nx; j++) {
07439 l = k + j;
07440 dgradient[l] = fabs(dgradient[l] - dgradient[l + nx]);
07441 }
07442 }
07443
07444 npix--;
07445 for (j = 0; j < nx; j++)
07446 dgradient[npix - j] = 0.0;
07447
07448 cpl_image_turn(gradient, -1);
07449 nx = cpl_image_get_size_x(gradient);
07450 ny = cpl_image_get_size_y(gradient);
07451 sgradient = mos_image_vertical_median_filter(gradient,
07452 filtbox, 0, ny, 0, step);
07453 cpl_image_delete(gradient);
07454
07455
07456
07457
07458
07459
07460 dgradient = cpl_image_get_data_float(sgradient);
07461
07462 for (i = 1; i <= ny; i += step) {
07463 row = cpl_vector_new_from_image_row(sgradient, i);
07464 srow = cpl_vector_filter_median_create(row, filtbox);
07465 cpl_vector_subtract(row, srow);
07466 cpl_vector_delete(srow);
07467 g = dgradient + (i-1)*nx;
07468 r = cpl_vector_get_data(row);
07469 for (j = 0; j < nx; j++)
07470 g[j] = r[j];
07471 cpl_vector_delete(row);
07472 }
07473
07474
07475
07476
07477
07478
07479
07480 mos_rotate_slits(slits, 1, nx, ny);
07481 xtop = cpl_table_get_data_double(slits, "xtop");
07482 ytop = cpl_table_get_data_double(slits, "ytop");
07483 xbottom = cpl_table_get_data_double(slits, "xbottom");
07484 ybottom = cpl_table_get_data_double(slits, "ybottom");
07485
07486
07487
07488
07489
07490
07491
07492 peaks = cpl_calloc(ny, sizeof(cpl_vector *));
07493
07494 for (i = 0; i < ny; i += step) {
07495 g = dgradient + i*nx;
07496 peaks[i] = mos_peak_candidates(g, nx, level, 1.0);
07497
07498
07499
07500 if (peaks[i])
07501 cpl_vector_subtract_scalar(peaks[i], 0.5);
07502
07503 }
07504
07505 cpl_image_delete(sgradient);
07506
07507
07508
07509
07510
07511
07512
07513
07514
07515 sradius = 5.0;
07516
07517
07518
07519
07520
07521
07522
07523
07524 tolerance = 0.9;
07525
07526
07527
07528
07529
07530
07531 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
07532 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
07533
07534
07535
07536
07537
07538
07539 nrows = (ny-1)/step + 1;
07540 traces = cpl_table_new(nrows);
07541 cpl_table_new_column(traces, "x", CPL_TYPE_DOUBLE);
07542 cpl_table_set_column_unit(traces, "x", "pixel");
07543 for (i = 0, j = 0; i < ny; i += step, j++)
07544 cpl_table_set(traces, "x", j, i);
07545
07546 for (i = 0; i < nslits; i++) {
07547
07548
07549
07550
07551
07552 ypos = ytop[i];
07553
07554 if (ypos < 0)
07555 ypos = 0;
07556 if (ypos >= ny)
07557 ypos = ny - 1;
07558
07559 pos = ypos / step;
07560 pos *= step;
07561
07562
07563
07564
07565
07566 if (peaks[pos]) {
07567 peak = cpl_vector_get_data(peaks[pos]);
07568 npeaks = cpl_vector_get_size(peaks[pos]);
07569
07570 min = fabs(peak[0] - xtop[i]);
07571 minpos = 0;
07572 for (j = 1; j < npeaks; j++) {
07573 dist = fabs(peak[j] - xtop[i]);
07574 if (min > dist) {
07575 min = dist;
07576 minpos = j;
07577 }
07578 }
07579 }
07580 else {
07581 npeaks = 0;
07582 }
07583
07584 snprintf(trace_id, MAX_COLNAME, "t%d", slit_id[i]);
07585 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
07586
07587 if (min > sradius || npeaks == 0) {
07588 cpl_msg_warning(func, "Cannot find spectrum edge for "
07589 "top (or left) end of slit %d", slit_id[i]);
07590 }
07591 else {
07592
07593
07594
07595
07596
07597
07598
07599
07600
07601 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
07602 start_y = peak[minpos];
07603
07604
07605
07606
07607
07608 prev_y = start_y;
07609
07610 for (j = pos + step; j < ny; j += step) {
07611 if (j - pos > pixel_above)
07612 break;
07613 if (peaks[j]) {
07614 peak = cpl_vector_get_data(peaks[j]);
07615 npeaks = cpl_vector_get_size(peaks[j]);
07616 min = fabs(peak[0] - prev_y);
07617 minpos = 0;
07618 for (k = 1; k < npeaks; k++) {
07619 dist = fabs(peak[k] - prev_y);
07620 if (min > dist) {
07621 min = dist;
07622 minpos = k;
07623 }
07624 }
07625 if (min < tolerance) {
07626 cpl_table_set(traces, trace_id, j/step,
07627 nx - peak[minpos]);
07628 prev_y = peak[minpos];
07629 }
07630 }
07631 }
07632
07633
07634
07635
07636
07637 prev_y = start_y;
07638
07639 for (j = pos - step; j >= 0; j -= step) {
07640 if (pos - j > pixel_below)
07641 break;
07642 if (peaks[j]) {
07643 peak = cpl_vector_get_data(peaks[j]);
07644 npeaks = cpl_vector_get_size(peaks[j]);
07645 min = fabs(peak[0] - prev_y);
07646 minpos = 0;
07647 for (k = 1; k < npeaks; k++) {
07648 dist = fabs(peak[k] - prev_y);
07649 if (min > dist) {
07650 min = dist;
07651 minpos = k;
07652 }
07653 }
07654 if (min < tolerance) {
07655 cpl_table_set(traces, trace_id, j/step,
07656 nx - peak[minpos]);
07657 prev_y = peak[minpos];
07658 }
07659 }
07660 }
07661 }
07662
07663
07664
07665
07666
07667
07668 if (peaks[pos]) {
07669 peak = cpl_vector_get_data(peaks[pos]);
07670 npeaks = cpl_vector_get_size(peaks[pos]);
07671
07672 min = fabs(peak[0] - xbottom[i]);
07673 minpos = 0;
07674 for (j = 1; j < npeaks; j++) {
07675 dist = fabs(peak[j] - xbottom[i]);
07676 if (min > dist) {
07677 min = dist;
07678 minpos = j;
07679 }
07680 }
07681 }
07682 else {
07683 npeaks = 0;
07684 }
07685
07686 snprintf(trace_id, MAX_COLNAME, "b%d", slit_id[i]);
07687 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
07688
07689 if (min > sradius || npeaks == 0) {
07690 cpl_msg_warning(func, "Cannot find spectrum edge for "
07691 "bottom (or right) end of slit %d", slit_id[i]);
07692 }
07693 else {
07694
07695 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
07696 start_y = peak[minpos];
07697
07698
07699
07700
07701
07702 prev_y = start_y;
07703
07704 for (j = pos + step; j < ny; j += step) {
07705 if (j - pos > pixel_above)
07706 break;
07707 if (peaks[j]) {
07708 peak = cpl_vector_get_data(peaks[j]);
07709 npeaks = cpl_vector_get_size(peaks[j]);
07710 min = fabs(peak[0] - prev_y);
07711 minpos = 0;
07712 for (k = 1; k < npeaks; k++) {
07713 dist = fabs(peak[k] - prev_y);
07714 if (min > dist) {
07715 min = dist;
07716 minpos = k;
07717 }
07718 }
07719 if (min < tolerance) {
07720 cpl_table_set(traces, trace_id, j/step,
07721 nx - peak[minpos]);
07722 prev_y = peak[minpos];
07723 }
07724 }
07725 }
07726
07727
07728
07729
07730
07731 prev_y = start_y;
07732
07733 for (j = pos - step; j >= 0; j -= step) {
07734 if (pos - j > pixel_below)
07735 break;
07736 if (peaks[j]) {
07737 peak = cpl_vector_get_data(peaks[j]);
07738 npeaks = cpl_vector_get_size(peaks[j]);
07739 min = fabs(peak[0] - prev_y);
07740 minpos = 0;
07741 for (k = 1; k < npeaks; k++) {
07742 dist = fabs(peak[k] - prev_y);
07743 if (min > dist) {
07744 min = dist;
07745 minpos = k;
07746 }
07747 }
07748 if (min < tolerance) {
07749 cpl_table_set(traces, trace_id, j/step,
07750 nx - peak[minpos]);
07751 prev_y = peak[minpos];
07752 }
07753 }
07754 }
07755 }
07756
07757 }
07758
07759 for (i = 0; i < ny; i += step)
07760 cpl_vector_delete(peaks[i]);
07761 cpl_free(peaks);
07762
07763
07764
07765
07766
07767 mos_rotate_slits(slits, -1, ny, nx);
07768
07769 return traces;
07770
07771 }
07772
07773
07794 cpl_table *mos_poly_trace(cpl_table *slits, cpl_table *traces, int order)
07795 {
07796 const char *func = "mos_poly_trace";
07797
07798 cpl_table *polytraces;
07799 cpl_table *dummy;
07800 cpl_vector *x;
07801 cpl_vector *trace;
07802 cpl_polynomial *polytrace;
07803 char trace_id[MAX_COLNAME];
07804 char trace_res[MAX_COLNAME];
07805 char trace_mod[MAX_COLNAME];
07806 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
07807
07808 double *xdata;
07809 int *slit_id;
07810 int nslits;
07811 int nrows;
07812 int npoints;
07813 int i, j, k;
07814
07815
07816 if (traces == NULL || slits == NULL) {
07817 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07818 return NULL;
07819 }
07820
07821 if (order > 5) {
07822 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07823 return NULL;
07824 }
07825
07826 nrows = cpl_table_get_nrow(traces);
07827 xdata = cpl_table_get_data_double(traces, "x");
07828 nslits = cpl_table_get_nrow(slits);
07829 slit_id = cpl_table_get_data_int(slits, "slit_id");
07830
07831 polytraces = cpl_table_new(2*nslits);
07832 cpl_table_new_column(polytraces, "slit_id", CPL_TYPE_INT);
07833 for (i = 0; i <= order; i++)
07834 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
07835
07836 for (i = 0; i < nslits; i++) {
07837 for (j = 0; j < 2; j++) {
07838
07839 if (j) {
07840 snprintf(trace_id, MAX_COLNAME, "b%d", slit_id[i]);
07841 snprintf(trace_res, MAX_COLNAME, "b%d_res", slit_id[i]);
07842 snprintf(trace_mod, MAX_COLNAME, "b%d_mod", slit_id[i]);
07843 }
07844 else {
07845 snprintf(trace_id, MAX_COLNAME, "t%d", slit_id[i]);
07846 snprintf(trace_res, MAX_COLNAME, "t%d_res", slit_id[i]);
07847 snprintf(trace_mod, MAX_COLNAME, "t%d_mod", slit_id[i]);
07848 }
07849
07850 cpl_table_set_int(polytraces, "slit_id", 2*i+j, slit_id[i]);
07851
07852
07853
07854
07855
07856
07857 dummy = cpl_table_new(nrows);
07858 cpl_table_duplicate_column(dummy, "x", traces, "x");
07859 cpl_table_duplicate_column(dummy, trace_id, traces, trace_id);
07860 npoints = nrows - cpl_table_count_invalid(dummy, trace_id);
07861 if (npoints < 2 * order) {
07862 cpl_table_delete(dummy);
07863 continue;
07864 }
07865 cpl_table_erase_invalid(dummy);
07866 x = cpl_vector_wrap(npoints,
07867 cpl_table_get_data_double(dummy, "x"));
07868 trace = cpl_vector_wrap(npoints,
07869 cpl_table_get_data_double(dummy, trace_id));
07870 polytrace = cpl_polynomial_fit_1d_create(x, trace, order, NULL);
07871 cpl_vector_unwrap(x);
07872 cpl_vector_unwrap(trace);
07873 cpl_table_delete(dummy);
07874
07875
07876
07877
07878
07879
07880
07881 k = 2;
07882 if (fabs(cpl_polynomial_get_coeff(polytrace, &k)) > 1.E-4) {
07883 cpl_polynomial_delete(polytrace);
07884 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
07885 cpl_table_duplicate_column(traces, trace_res, traces,
07886 trace_mod);
07887 if (j)
07888 cpl_msg_warning(func, "Exclude bad curvature solution "
07889 "for bottom (right) edge of slit %d", slit_id[i]);
07890 else
07891 cpl_msg_warning(func, "Exclude bad curvature solution "
07892 "for top (left) edge of slit %d", slit_id[i]);
07893 continue;
07894 }
07895
07896
07897
07898
07899
07900
07901 for (k = 0; k <= order; k++)
07902 cpl_table_set_double(polytraces, clab[k], 2*i+j,
07903 cpl_polynomial_get_coeff(polytrace, &k));
07904
07905
07906
07907
07908
07909 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
07910 cpl_table_set_column_unit(traces, trace_mod, "pixel");
07911
07912 for (k = 0; k < nrows; k++) {
07913 cpl_table_set_double(traces, trace_mod, k,
07914 cpl_polynomial_eval_1d(polytrace, xdata[k], NULL));
07915 }
07916
07917 cpl_polynomial_delete(polytrace);
07918
07919 cpl_table_duplicate_column(traces, trace_res, traces, trace_mod);
07920 cpl_table_subtract_columns(traces, trace_res, trace_id);
07921 cpl_table_multiply_scalar(traces, trace_res, -1.0);
07922
07923 }
07924 }
07925
07926 return polytraces;
07927
07928 }
07929
07930
07954 cpl_error_code mos_global_trace(cpl_table *slits, cpl_table *polytraces,
07955 int mode)
07956 {
07957 const char *func = "mos_global_trace";
07958
07959 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
07960
07961 cpl_table *table;
07962 cpl_vector *c0;
07963 cpl_vector *cn;
07964 cpl_bivector *list;
07965
07966
07967
07968
07969 double *offset;
07970 double rms, q, m;
07971
07972 int order, nrows, nslits;
07973 int i, j;
07974
07975
07976 if (polytraces == NULL) {
07977 cpl_msg_error(func, "Missing spectral curvature table");
07978 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07979 }
07980
07981 if (slits == NULL) {
07982 cpl_msg_error(func, "Missing slits positions table");
07983 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07984 }
07985
07986 nslits = cpl_table_get_nrow(slits);
07987
07988 table = cpl_table_duplicate(polytraces);
07989 cpl_table_erase_invalid(table);
07990
07991 nrows = cpl_table_get_nrow(table);
07992
07993 if (nrows < 4) {
07994 cpl_msg_warning(func, "Too few successful spectral curvature tracings "
07995 "(%d): the determination of a global curvature model "
07996 "failed", nrows);
07997 return CPL_ERROR_NONE;
07998 }
07999
08000 order = cpl_table_get_ncol(polytraces) - 2;
08001
08002 for (i = 0; i <= order; i++) {
08003 if (!cpl_table_has_column(table, clab[i])) {
08004 cpl_msg_error(func, "Wrong spectral curvature table");
08005 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08006 }
08007 }
08008
08009
08010
08011
08012
08013
08014 for (i = 0; i < nslits; i++) {
08015 if (!cpl_table_is_valid(polytraces, clab[0], 2*i)) {
08016 cpl_table_set_double(polytraces, clab[0], 2*i,
08017 cpl_table_get_double(slits, "ytop", i, NULL));
08018 }
08019 if (!cpl_table_is_valid(polytraces, clab[0], 2*i+1)) {
08020 cpl_table_set_double(polytraces, clab[0], 2*i+1,
08021 cpl_table_get_double(slits, "ybottom", i, NULL));
08022 }
08023 }
08024
08025 offset = cpl_table_get_data_double(polytraces, clab[0]);
08026
08027
08028
08029
08030
08031
08032 c0 = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[0]));
08033
08034 for (i = 1; i <= order; i++) {
08035 cn = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[i]));
08036 list = cpl_bivector_wrap_vectors(c0, cn);
08037 robustLinearFit(list, &q, &m, &rms);
08038
08039
08040
08041 for (j = 0; j < 2*nslits; j++) {
08042 if (mode == 1)
08043 if (cpl_table_is_valid(polytraces, clab[i], j))
08044 continue;
08045 cpl_table_set_double(polytraces, clab[i], j, offset[j]*m + q);
08046
08047
08048
08049
08050 }
08051 cpl_bivector_unwrap_vectors(list);
08052
08053
08054
08055 cpl_vector_unwrap(cn);
08056 }
08057
08058 cpl_vector_unwrap(c0);
08059 cpl_table_delete(table);
08060
08061 return CPL_ERROR_NONE;
08062
08063 }
08064
08065
08135 cpl_image *mos_spatial_calibration(cpl_image *spectra, cpl_table *slits,
08136 cpl_table *polytraces, double reference,
08137 double blue, double red, double dispersion,
08138 int flux, cpl_image *calibration)
08139 {
08140 const char *func = "mos_spatial_calibration";
08141
08142 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
08143
08144 cpl_polynomial *polytop;
08145 cpl_polynomial *polybot;
08146 cpl_image **exslit;
08147 cpl_image *resampled;
08148 float *data;
08149 float *sdata;
08150 float *xdata;
08151 double vtop, vbot, value;
08152 double top, bot;
08153 double coeff;
08154 double ytop, ybot;
08155 double ypos, yfra;
08156 double factor;
08157 int yint, ysize, yprev;
08158 int nslits;
08159 int npseudo;
08160 int *slit_id;
08161 int *length;
08162 int nx, ny;
08163 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
08164 int missing_top, missing_bot;
08165 int null;
08166 int order;
08167 int i, j, k;
08168
08169 int create_position = 1;
08170
08171
08172 if (spectra == NULL || slits == NULL || polytraces == NULL) {
08173 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08174 return NULL;
08175 }
08176
08177 if (dispersion <= 0.0) {
08178 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08179 return NULL;
08180 }
08181
08182 if (red - blue < dispersion) {
08183 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08184 return NULL;
08185 }
08186
08187 nx = cpl_image_get_size_x(spectra);
08188 ny = cpl_image_get_size_y(spectra);
08189 sdata = cpl_image_get_data(spectra);
08190 if (calibration)
08191 data = cpl_image_get_data(calibration);
08192
08193 if (cpl_table_has_column(slits, "position"))
08194 create_position = 0;
08195
08196 if (create_position) {
08197 cpl_table_new_column(slits, "position", CPL_TYPE_INT);
08198 cpl_table_new_column(slits, "length", CPL_TYPE_INT);
08199 cpl_table_set_column_unit(slits, "position", "pixel");
08200 cpl_table_set_column_unit(slits, "length", "pixel");
08201 }
08202 else
08203 length = cpl_table_get_data_int(slits, "length");
08204
08205 nslits = cpl_table_get_nrow(slits);
08206 slit_id = cpl_table_get_data_int(slits, "slit_id");
08207 order = cpl_table_get_ncol(polytraces) - 2;
08208
08209
08210
08211
08212
08213
08214 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
08215 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
08216
08217 exslit = cpl_calloc(nslits, sizeof(cpl_image *));
08218
08219 for (i = 0; i < nslits; i++) {
08220
08221 if (create_position == 0)
08222 if (length[i] == 0)
08223 continue;
08224
08225
08226
08227
08228
08229
08230
08231
08232
08233
08234
08235
08236 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
08237
08238 start_pixel = refpixel - pixel_below;
08239 if (start_pixel < 0)
08240 start_pixel = 0;
08241
08242 end_pixel = refpixel + pixel_above;
08243 if (end_pixel > nx)
08244 end_pixel = nx;
08245
08246
08247
08248
08249
08250
08251 missing_top = 0;
08252 polytop = cpl_polynomial_new(1);
08253 for (k = 0; k <= order; k++) {
08254 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
08255 if (null) {
08256 cpl_polynomial_delete(polytop);
08257 missing_top = 1;
08258 break;
08259 }
08260 cpl_polynomial_set_coeff(polytop, &k, coeff);
08261 }
08262
08263 missing_bot = 0;
08264 polybot = cpl_polynomial_new(1);
08265 for (k = 0; k <= order; k++) {
08266 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
08267 if (null) {
08268 cpl_polynomial_delete(polybot);
08269 missing_bot = 1;
08270 break;
08271 }
08272 cpl_polynomial_set_coeff(polybot, &k, coeff);
08273 }
08274
08275 if (missing_top && missing_bot) {
08276 cpl_msg_warning(func, "Spatial calibration, slit %d was not "
08277 "traced: no extraction!",
08278 slit_id[i]);
08279 continue;
08280 }
08281
08282
08283
08284
08285
08286
08287
08288 if (missing_top) {
08289 cpl_msg_warning(func, "Upper edge of slit %d was not traced: "
08290 "the spectral curvature of the lower edge "
08291 "is used instead.", slit_id[i]);
08292 polytop = cpl_polynomial_duplicate(polybot);
08293 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
08294 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
08295 k = 0;
08296 coeff = cpl_polynomial_get_coeff(polybot, &k);
08297 coeff += ytop - ybot;
08298 cpl_polynomial_set_coeff(polytop, &k, coeff);
08299 }
08300
08301 if (missing_bot) {
08302 cpl_msg_warning(func, "Lower edge of slit %d was not traced: "
08303 "the spectral curvature of the upper edge "
08304 "is used instead.", slit_id[i]);
08305 polybot = cpl_polynomial_duplicate(polytop);
08306 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
08307 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
08308 k = 0;
08309 coeff = cpl_polynomial_get_coeff(polytop, &k);
08310 coeff -= ytop - ybot;
08311 cpl_polynomial_set_coeff(polybot, &k, coeff);
08312 }
08313
08314
08315
08316
08317
08318 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
08319 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
08320 npseudo = ceil(top-bot) + 1;
08321
08322 if (npseudo < 1) {
08323 cpl_polynomial_delete(polytop);
08324 cpl_polynomial_delete(polybot);
08325 cpl_msg_warning(func, "Slit %d was badly traced: no extraction!",
08326 slit_id[i]);
08327 continue;
08328 }
08329
08330 exslit[i] = cpl_image_new(nx, npseudo+1, CPL_TYPE_FLOAT);
08331 xdata = cpl_image_get_data(exslit[i]);
08332
08333
08334
08335
08336
08337 for (j = start_pixel; j < end_pixel; j++) {
08338 top = cpl_polynomial_eval_1d(polytop, j, NULL);
08339 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
08340 factor = (top-bot)/npseudo;
08341 for (k = 0; k <= npseudo; k++) {
08342 ypos = top - k*factor;
08343 yint = ypos;
08344 yfra = ypos - yint;
08345 if (yint >= 0 && yint < ny-1) {
08346 vtop = sdata[j + nx*yint];
08347 vbot = sdata[j + nx*(yint+1)];
08348 value = vtop*(1-yfra) + vbot*yfra;
08349 if (flux)
08350 value *= factor;
08351 xdata[j + nx*(npseudo-k)] = value;
08352 if (calibration) {
08353 data[j + nx*yint] = (top-yint)/factor;
08354 if (k) {
08355
08356
08357
08358
08359
08360
08361
08362 if (yprev - yint > 1) {
08363 data[j + nx*(yint+1)] = (top-yint-1)/factor;
08364 }
08365 }
08366 }
08367 }
08368 yprev = yint;
08369 }
08370 }
08371 cpl_polynomial_delete(polytop);
08372 cpl_polynomial_delete(polybot);
08373 }
08374
08375
08376
08377
08378
08379 ysize = 0;
08380 for (i = 0; i < nslits; i++)
08381 if (exslit[i])
08382 ysize += cpl_image_get_size_y(exslit[i]);
08383
08384 resampled = cpl_image_new(nx, ysize, CPL_TYPE_FLOAT);
08385
08386 yint = -1;
08387 for (i = 0; i < nslits; i++) {
08388 if (exslit[i]) {
08389 yint += cpl_image_get_size_y(exslit[i]);
08390 cpl_image_copy(resampled, exslit[i], 1, ysize - yint);
08391 if (create_position) {
08392 cpl_table_set_int(slits, "position", i, ysize - yint - 1);
08393 cpl_table_set_int(slits, "length", i,
08394 cpl_image_get_size_y(exslit[i]));
08395 }
08396 cpl_image_delete(exslit[i]);
08397 }
08398 else if (create_position) {
08399 cpl_table_set_int(slits, "position", i, -1);
08400 cpl_table_set_int(slits, "length", i, 0);
08401 }
08402 }
08403
08404
08405
08406
08407
08408
08409
08410
08411
08412
08413
08414
08415
08416
08417
08418
08419
08420 cpl_free(exslit);
08421
08422 return resampled;
08423
08424 }
08425
08426
08533 cpl_image *mos_wavelength_calibration_final(cpl_image *image, cpl_table *slits,
08534 cpl_vector *lines,
08535 double dispersion, float level,
08536 int sradius, int order,
08537 double reject, double refwave,
08538 double *wavestart, double *waveend,
08539 int *nlines, double *error,
08540 cpl_table *idscoeff,
08541 cpl_image *calibration,
08542 cpl_image *residuals,
08543 cpl_table *restable)
08544 {
08545
08546 const char *func = "mos_wavelength_calibration_final";
08547
08548 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
08549
08550
08551 double tolerance = 20.0;
08552 int step = 10;
08553
08554 char name[MAX_COLNAME];
08555
08556 cpl_image *resampled;
08557 cpl_bivector *output;
08558 cpl_vector *wavel;
08559 cpl_vector *peaks;
08560 cpl_polynomial *ids;
08561 cpl_polynomial *lin;
08562 cpl_polynomial *fguess;
08563 cpl_table *coeff;
08564 double ids_err;
08565 double max_disp, min_disp;
08566 double *line;
08567 double firstLambda, lastLambda, lambda;
08568 double wave, pixe, value;
08569 double c;
08570 float *sdata;
08571 float *rdata;
08572 float *idata;
08573 float *ddata;
08574 float v1, v2, vi;
08575 float fpixel;
08576 int *length;
08577 int pixstart, pixend;
08578 int row_top, row_bot;
08579 int extrapolation;
08580 int nref;
08581 int nslits;
08582 int nfits;
08583 int nl, nx, ny, pixel;
08584 int countLines, usedLines;
08585 int uorder;
08586 int missing;
08587 int null;
08588 int width, uradius;
08589 int i, j, k, s;
08590
08591
08592 if (dispersion == 0.0) {
08593 cpl_msg_error(func, "The expected dispersion (A/pixel) must be given");
08594 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08595 return NULL;
08596 }
08597
08598 if (dispersion < 0.0) {
08599 cpl_msg_error(func, "The expected dispersion must be positive");
08600 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08601 return NULL;
08602 }
08603
08604 if (idscoeff == NULL) {
08605 cpl_msg_error(func, "A preallocated IDS coeff table must be given");
08606 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08607 return NULL;
08608 }
08609
08610 max_disp = dispersion + dispersion * tolerance / 100;
08611 min_disp = dispersion - dispersion * tolerance / 100;
08612
08613 if (order < 1) {
08614 cpl_msg_error(func, "The order of the fitting polynomial "
08615 "must be at least 1");
08616 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08617 return NULL;
08618 }
08619
08620 if (image == NULL || lines == NULL) {
08621 cpl_msg_error(func, "Both spectral exposure and reference line "
08622 "catalog are required in input");
08623 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08624 return NULL;
08625 }
08626
08627 nx = cpl_image_get_size_x(image);
08628 ny = cpl_image_get_size_y(image);
08629 sdata = cpl_image_get_data_float(image);
08630
08631 nref = cpl_vector_get_size(lines);
08632 line = cpl_vector_get_data(lines);
08633
08634 if (*wavestart < 1.0 && *waveend < 1.0) {
08635 firstLambda = line[0];
08636 lastLambda = line[nref-1];
08637 extrapolation = (lastLambda - firstLambda) / 10;
08638 firstLambda -= extrapolation;
08639 lastLambda += extrapolation;
08640 *wavestart = firstLambda;
08641 *waveend = lastLambda;
08642 }
08643 else {
08644 firstLambda = *wavestart;
08645 lastLambda = *waveend;
08646 }
08647
08648 nl = (lastLambda - firstLambda) / dispersion;
08649 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
08650 rdata = cpl_image_get_data_float(resampled);
08651
08652
08653
08654
08655
08656 for (j = 0; j <= order; j++)
08657 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
08658
08659 if (calibration)
08660 idata = cpl_image_get_data_float(calibration);
08661
08662 if (residuals)
08663 ddata = cpl_image_get_data_float(residuals);
08664
08665 if (restable) {
08666 cpl_table_set_size(restable, nref);
08667 cpl_table_new_column(restable, "wavelength", CPL_TYPE_DOUBLE);
08668 cpl_table_copy_data_double(restable, "wavelength", line);
08669 for (i = 0; i < ny; i += step) {
08670 snprintf(name, MAX_COLNAME, "r%d", i);
08671 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
08672 snprintf(name, MAX_COLNAME, "d%d", i);
08673 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
08674 snprintf(name, MAX_COLNAME, "p%d", i);
08675 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
08676 }
08677 }
08678
08679
08680
08681
08682
08683
08684 nslits = cpl_table_get_nrow(slits);
08685 length = cpl_table_get_data_int(slits, "length");
08686
08687 row_top = ny;
08688 for (s = 0; s < nslits; s++) {
08689
08690 if (length[s] == 0)
08691 continue;
08692
08693
08694
08695
08696
08697
08698 row_bot = cpl_table_get_int(slits, "position", s, NULL);
08699
08700 if (sradius > 0) {
08701
08702
08703
08704
08705
08706
08707
08708
08709
08710 coeff = cpl_table_new(row_top - row_bot);
08711 for (j = 0; j <= order; j++)
08712 cpl_table_new_column(coeff, clab[j], CPL_TYPE_DOUBLE);
08713 }
08714
08715
08716
08717
08718
08719
08720 for (i = row_bot; i < row_top; i++) {
08721 width = mos_lines_width(sdata + i*nx, nx);
08722 if (width < 5)
08723 width = 5;
08724 peaks = mos_peak_candidates(sdata + i*nx, nx, level, width);
08725 if (peaks) {
08726 peaks = mos_refine_peaks(sdata + i*nx, nx, peaks, width);
08727 }
08728 if (peaks) {
08729 int keep_multiplex = mos_multiplex;
08730 mos_multiplex = -1;
08731 output = mos_identify_peaks(peaks, lines,
08732 min_disp, max_disp, 0.05);
08733 mos_multiplex = keep_multiplex;
08734 if (output) {
08735 countLines = cpl_bivector_get_size(output);
08736 if (countLines < 4) {
08737 cpl_bivector_delete(output);
08738 cpl_vector_delete(peaks);
08739 if (nlines)
08740 nlines[i] = 0;
08741 if (error)
08742 error[i] = 0.0;
08743 continue;
08744 }
08745
08746
08747
08748
08749
08750 wavel = cpl_bivector_get_y(output);
08751 cpl_vector_subtract_scalar(wavel, refwave);
08752
08753 uorder = countLines / 2 - 1;
08754 if (uorder > order)
08755 uorder = order;
08756
08757 ids = mos_poly_wav2pix(output, uorder, reject,
08758 2 * (uorder + 1), &usedLines,
08759 &ids_err);
08760
08761 if (ids == NULL) {
08762 cpl_bivector_delete(output);
08763 cpl_vector_delete(peaks);
08764 if (nlines)
08765 nlines[i] = 0;
08766 if (error)
08767 error[i] = 0.0;
08768 cpl_error_reset();
08769 continue;
08770 }
08771
08772 if (sradius > 0) {
08773 for (k = 0; k <= order; k++) {
08774 if (k > uorder) {
08775 cpl_table_set_double(coeff, clab[k],
08776 i - row_bot, 0.0);
08777 }
08778 else {
08779 cpl_table_set_double(coeff, clab[k],
08780 i - row_bot, cpl_polynomial_get_coeff(ids, &k));
08781 }
08782 }
08783 }
08784
08785 if (calibration) {
08786 pixstart = cpl_polynomial_eval_1d(ids,
08787 cpl_bivector_get_y_data(output)[0],
08788 NULL);
08789 pixend = cpl_polynomial_eval_1d(ids,
08790 cpl_bivector_get_y_data(output)[countLines-1],
08791 NULL);
08792 extrapolation = (pixend - pixstart) / 5;
08793 pixstart -= extrapolation;
08794 pixend += extrapolation;
08795 if (pixstart < 0)
08796 pixstart = 0;
08797 if (pixend > nx)
08798 pixend = nx;
08799
08800 for (j = pixstart; j < pixend; j++) {
08801 (idata + i*nx)[j] = mos_eval_dds(ids,
08802 firstLambda, lastLambda, refwave, j);
08803 }
08804 }
08805
08806
08807
08808
08809
08810 if (residuals || (restable && !(i%step))) {
08811 if (restable && !(i%step)) {
08812 lin = cpl_polynomial_new(1);
08813 for (k = 0; k < 2; k++)
08814 cpl_polynomial_set_coeff(lin, &k,
08815 cpl_polynomial_get_coeff(ids, &k));
08816 }
08817 for (j = 0; j < countLines; j++) {
08818 pixe = cpl_bivector_get_x_data(output)[j];
08819 wave = cpl_bivector_get_y_data(output)[j];
08820 value = pixe
08821 - cpl_polynomial_eval_1d(ids, wave, NULL);
08822 if (residuals) {
08823 pixel = pixe + 0.5;
08824 (ddata + i*nx)[pixel] = value;
08825 }
08826 if (restable && !(i%step)) {
08827 for (k = 0; k < nref; k++) {
08828 if (fabs(line[k]-refwave-wave) < 0.1) {
08829 snprintf(name, MAX_COLNAME,
08830 "r%d", i);
08831 cpl_table_set_double(restable, name,
08832 k, value);
08833 value = pixe
08834 - cpl_polynomial_eval_1d(lin,
08835 wave, NULL);
08836 snprintf(name, MAX_COLNAME,
08837 "d%d", i);
08838 cpl_table_set_double(restable, name,
08839 k, value);
08840 snprintf(name, MAX_COLNAME,
08841 "p%d", i);
08842 cpl_table_set_double(restable, name,
08843 k, pixe);
08844 break;
08845 }
08846 }
08847 }
08848 }
08849 if (restable && !(i%step)) {
08850 cpl_polynomial_delete(lin);
08851 }
08852
08853
08854
08855
08856
08857
08858
08859
08860
08861
08862
08863 }
08864
08865
08866
08867
08868
08869
08870
08871
08872 if (nlines)
08873 nlines[i] = usedLines;
08874 if (error)
08875 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
08876
08877 for (k = 0; k <= order; k++) {
08878 if (k > uorder) {
08879 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
08880 }
08881 else {
08882 cpl_table_set_double(idscoeff, clab[k], i,
08883 cpl_polynomial_get_coeff(ids, &k));
08884 }
08885 }
08886
08887 cpl_polynomial_delete(ids);
08888 cpl_bivector_delete(output);
08889 }
08890 cpl_vector_delete(peaks);
08891 }
08892 }
08893
08894
08895 if (sradius > 0) {
08896
08897
08898
08899
08900
08901 nfits = row_top - row_bot - cpl_table_count_invalid(coeff, clab[0]);
08902
08903 if (nfits) {
08904 int slope = 0;
08905
08906 fguess = cpl_polynomial_new(1);
08907
08908 if (mos_interpolate_wavecalib(coeff, NULL, 2, 1)) {
08909
08910 slope = 0;
08911
08912
08913
08914
08915
08916 for (k = 0; k <= order; k++) {
08917 c = cpl_table_get_column_median(coeff, clab[k]);
08918 cpl_polynomial_set_coeff(fguess, &k, c);
08919 }
08920 }
08921 else {
08922 slope = 1;
08923 }
08924
08925 for (i = row_bot; i < row_top; i++) {
08926
08927
08928
08929
08930
08931 width = mos_lines_width(sdata + i*nx, nx);
08932 if (width > sradius) {
08933 uradius = width;
08934 }
08935 else {
08936 uradius = sradius;
08937 }
08938
08939 if (slope) {
08940 for (k = 0; k <= order; k++) {
08941 c = cpl_table_get_double(coeff, clab[k],
08942 i - row_bot, NULL);
08943 cpl_polynomial_set_coeff(fguess, &k, c);
08944 }
08945 }
08946
08947 output = mos_find_peaks(sdata + i*nx, nx, lines,
08948 fguess, refwave, uradius);
08949
08950 if (output == NULL) {
08951 cpl_error_reset();
08952 continue;
08953 }
08954
08955 countLines = cpl_bivector_get_size(output);
08956
08957 if (countLines < 4) {
08958 cpl_bivector_delete(output);
08959 continue;
08960 }
08961
08962
08963
08964
08965
08966 wavel = cpl_bivector_get_y(output);
08967 cpl_vector_subtract_scalar(wavel, refwave);
08968
08969 uorder = countLines / 2 - 1;
08970 if (uorder > order)
08971 uorder = order;
08972
08973 ids = mos_poly_wav2pix(output, uorder, reject,
08974 2 * (uorder + 1), &usedLines,
08975 &ids_err);
08976
08977 if (ids == NULL) {
08978 cpl_error_reset();
08979 cpl_bivector_delete(output);
08980 continue;
08981 }
08982
08983 if (nlines)
08984 nlines[i] = usedLines;
08985 if (error)
08986 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
08987
08988 if (calibration) {
08989 pixstart = cpl_polynomial_eval_1d(ids,
08990 cpl_bivector_get_y_data(output)[0],
08991 NULL);
08992 pixend = cpl_polynomial_eval_1d(ids,
08993 cpl_bivector_get_y_data(output)[countLines-1],
08994 NULL);
08995 extrapolation = (pixend - pixstart) / 5;
08996 pixstart -= extrapolation;
08997 pixend += extrapolation;
08998 if (pixstart < 0)
08999 pixstart = 0;
09000 if (pixend > nx)
09001 pixend = nx;
09002
09003 for (j = pixstart; j < pixend; j++) {
09004 (idata + i*nx)[j] = mos_eval_dds(ids,
09005 firstLambda, lastLambda, refwave, j);
09006 }
09007 }
09008
09009
09010
09011
09012
09013 if (residuals || (restable && !(i%step))) {
09014 if (restable && !(i%step)) {
09015 lin = cpl_polynomial_new(1);
09016 for (k = 0; k < 2; k++)
09017 cpl_polynomial_set_coeff(lin, &k,
09018 cpl_polynomial_get_coeff(ids, &k));
09019 }
09020 for (j = 0; j < countLines; j++) {
09021 pixe = cpl_bivector_get_x_data(output)[j];
09022 wave = cpl_bivector_get_y_data(output)[j];
09023 value = pixe
09024 - cpl_polynomial_eval_1d(ids, wave, NULL);
09025 if (residuals) {
09026 pixel = pixe + 0.5;
09027 (ddata + i*nx)[pixel] = value;
09028 }
09029 if (restable && !(i%step)) {
09030 for (k = 0; k < nref; k++) {
09031 if (fabs(line[k]-refwave-wave) < 0.1) {
09032 snprintf(name, MAX_COLNAME,
09033 "r%d", i);
09034 cpl_table_set_double(restable, name,
09035 k, value);
09036 value = pixe
09037 - cpl_polynomial_eval_1d(lin,
09038 wave, NULL);
09039 snprintf(name, MAX_COLNAME,
09040 "d%d", i);
09041 cpl_table_set_double(restable, name,
09042 k, value);
09043 snprintf(name, MAX_COLNAME,
09044 "p%d", i);
09045 cpl_table_set_double(restable, name,
09046 k, pixe);
09047 break;
09048 }
09049 }
09050 }
09051 }
09052 if (restable && !(i%step)) {
09053 cpl_polynomial_delete(lin);
09054 }
09055
09056
09057
09058
09059
09060
09061
09062
09063
09064
09065
09066 }
09067
09068 for (k = 0; k <= order; k++) {
09069 if (k > uorder) {
09070 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
09071 }
09072 else {
09073 cpl_table_set_double(idscoeff, clab[k], i,
09074 cpl_polynomial_get_coeff(ids, &k));
09075 }
09076 }
09077
09078 cpl_bivector_delete(output);
09079 cpl_polynomial_delete(ids);
09080
09081 }
09082
09083 cpl_polynomial_delete(fguess);
09084 }
09085
09086 cpl_table_delete(coeff);
09087
09088 }
09089
09090 row_top = row_bot;
09091
09092 }
09093
09094
09095
09096
09097
09098
09099
09100
09101
09102 for (i = 0; i < ny; i++) {
09103
09104 missing = 0;
09105 ids = cpl_polynomial_new(1);
09106 for (k = 0; k <= order; k++) {
09107 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
09108 if (null) {
09109 cpl_polynomial_delete(ids);
09110 missing = 1;
09111 break;
09112 }
09113 cpl_polynomial_set_coeff(ids, &k, c);
09114 }
09115 if (missing)
09116 continue;
09117
09118 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
09119 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
09120 if (pixstart < 0)
09121 pixstart = 0;
09122 if (pixend > nx)
09123 pixend = nx;
09124
09125
09126
09127
09128
09129 for (j = 0; j < nl; j++) {
09130 lambda = firstLambda + j * dispersion;
09131 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave, NULL);
09132 pixel = fpixel;
09133 if (pixel >= 0 && pixel < nx-1) {
09134 v1 = (sdata + i*nx)[pixel];
09135 v2 = (sdata + i*nx)[pixel+1];
09136 vi = v1 + (v2-v1)*(fpixel-pixel);
09137 (rdata + i*nl)[j] = vi;
09138 }
09139 }
09140
09141 cpl_polynomial_delete(ids);
09142 }
09143
09144 return resampled;
09145 }
09146
09147
09174 cpl_image *mos_wavelength_calibration(cpl_image *image, double refwave,
09175 double firstLambda, double lastLambda,
09176 double dispersion, cpl_table *idscoeff,
09177 int flux)
09178 {
09179
09180 const char *func = "mos_wavelength_calibration";
09181
09182 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
09183
09184
09185 cpl_image *resampled;
09186 cpl_polynomial *ids;
09187 double pixel_per_lambda;
09188 double lambda;
09189 double c;
09190 float *sdata;
09191 float *rdata;
09192 float v0, v1, v2, v3, vi;
09193 float fpixel;
09194 int order;
09195 int pixstart, pixend;
09196 int nl, nx, ny, pixel;
09197 int missing;
09198 int null;
09199 int i, j, k;
09200
09201
09202 if (dispersion <= 0.0) {
09203 cpl_msg_error(func, "The resampling step must be positive");
09204 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
09205 return NULL;
09206 }
09207
09208 if (lastLambda - firstLambda < dispersion) {
09209 cpl_msg_error(func, "Invalid spectral range: %.2f to %.2f",
09210 firstLambda, lastLambda);
09211 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
09212 return NULL;
09213 }
09214
09215 if (idscoeff == NULL) {
09216 cpl_msg_error(func, "An IDS coeff table must be given");
09217 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09218 return NULL;
09219 }
09220
09221 if (image == NULL) {
09222 cpl_msg_error(func, "A scientific spectral image must be given");
09223 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09224 return NULL;
09225 }
09226
09227 nx = cpl_image_get_size_x(image);
09228 ny = cpl_image_get_size_y(image);
09229 sdata = cpl_image_get_data_float(image);
09230
09231 nl = (lastLambda - firstLambda) / dispersion;
09232 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
09233 rdata = cpl_image_get_data_float(resampled);
09234
09235 order = 0;
09236 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
09237 ++order;
09238 --order;
09239
09240 for (i = 0; i < ny; i++) {
09241
09242 missing = 0;
09243 ids = cpl_polynomial_new(1);
09244 for (k = 0; k <= order; k++) {
09245 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
09246 if (null) {
09247 cpl_polynomial_delete(ids);
09248 missing = 1;
09249 break;
09250 }
09251 cpl_polynomial_set_coeff(ids, &k, c);
09252 }
09253 if (missing)
09254 continue;
09255
09256 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
09257 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
09258 if (pixstart < 0)
09259 pixstart = 0;
09260 if (pixend > nx)
09261 pixend = nx;
09262
09263
09264
09265
09266
09267 for (j = 0; j < nl; j++) {
09268 lambda = firstLambda + j * dispersion;
09269 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
09270 &pixel_per_lambda);
09271
09272
09273
09274
09275
09276
09277
09278 pixel = fpixel;
09279
09280
09281 if (1) {
09282
09283
09284
09285
09286
09287
09288 if (pixel >= 1 && pixel < nx-2) {
09289 v0 = (sdata + i*nx)[pixel-1];
09290 v1 = (sdata + i*nx)[pixel];
09291 v2 = (sdata + i*nx)[pixel+1];
09292 v3 = (sdata + i*nx)[pixel+2];
09293 vi = (fpixel-pixel)*(fpixel-pixel)*(v3 - v2 - v1 + v0)
09294 + (fpixel-pixel)*(3*v2 - v3 - v1 - v0)
09295 + 2*v1;
09296 vi /= 2;
09297 if (v1 > v2) {
09298 if (vi > v1) {
09299 vi = v1;
09300 }
09301 else if (vi < v2) {
09302 vi = v2;
09303 }
09304 }
09305 else {
09306 if (vi > v2) {
09307 vi = v2;
09308 }
09309 else if (vi < v1) {
09310 vi = v1;
09311 }
09312 }
09313 if (flux)
09314 vi *= dispersion * pixel_per_lambda;
09315 (rdata + i*nl)[j] = vi;
09316 }
09317 else if (pixel >= 0 && pixel < nx-1) {
09318 v1 = (sdata + i*nx)[pixel];
09319 v2 = (sdata + i*nx)[pixel+1];
09320 vi = v1 + (v2-v1)*(fpixel-pixel);
09321 if (flux)
09322 vi *= dispersion * pixel_per_lambda;
09323 (rdata + i*nl)[j] = vi;
09324 }
09325 }
09326 else {
09327
09328
09329
09330
09331
09332
09333
09334
09335
09336
09337 double spos = fpixel - dispersion * pixel_per_lambda / 2;
09338 double epos = fpixel + dispersion * pixel_per_lambda / 2;
09339
09340
09341
09342
09343
09344 int spix = spos;
09345 int epix = epos + 1;
09346
09347 if (spix < 0)
09348 spix = 0;
09349
09350 if (epix > nx)
09351 epix = nx;
09352
09353 vi = 0.0;
09354 for (k = spix; k < epix; k++) {
09355 if (pixel >= 0 && pixel < nx) {
09356 vi += (sdata + i*nx)[k];
09357 }
09358 }
09359
09360
09361
09362
09363
09364
09365
09366
09367 vi *= dispersion * pixel_per_lambda / (epix - spix);
09368
09369
09370
09371
09372
09373
09374 if (flux)
09375 vi *= dispersion * pixel_per_lambda;
09376
09377 (rdata + i*nl)[j] = vi;
09378 }
09379 }
09380
09381 cpl_polynomial_delete(ids);
09382 }
09383
09384 return resampled;
09385 }
09386
09387
09454 cpl_table *mos_wavelength_align(cpl_image *image, cpl_table *slits,
09455 double refwave, double firstLambda,
09456 double lastLambda, cpl_table *idscoeff,
09457 cpl_vector *skylines, int highres, int order,
09458 cpl_image *calibration, int sradius)
09459 {
09460 const char *func = "mos_wavelength_align";
09461
09462 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
09463
09464 double *line;
09465 double *data;
09466 double expPos, offset;
09467 double c;
09468 double lambda1, lambda2;
09469 double rms;
09470 float pos;
09471 float *sdata;
09472 float *cdata;
09473 int *idata;
09474 int startPos, endPos;
09475 int window = 2*sradius + 1;
09476 int nlines;
09477 int nslits;
09478 int npoints;
09479 int nrows;
09480 int nx, ny;
09481 int xlow, ylow, xhig, yhig;
09482 int idsorder, uorder;
09483 int *slit_id;
09484 int *position;
09485 int *length;
09486 int missing;
09487 int null;
09488 int i, j, k;
09489
09490 char offname[MAX_COLNAME];
09491 char name[MAX_COLNAME];
09492
09493 cpl_polynomial *ids;
09494 cpl_polynomial *polycorr;
09495 cpl_image *exslit;
09496 cpl_image *sky;
09497 cpl_table *offsets;
09498 cpl_table *dummy;
09499 cpl_vector *wave;
09500 cpl_vector *offs;
09501
09502
09503 if (idscoeff == NULL) {
09504 cpl_msg_error(func, "An IDS coeff table must be given");
09505 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09506 return NULL;
09507 }
09508
09509 if (image == NULL) {
09510 cpl_msg_error(func, "A scientific spectral image must be given");
09511 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09512 return NULL;
09513 }
09514
09515 if (slits == NULL) {
09516 cpl_msg_error(func, "A slit position table must be given");
09517 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09518 return NULL;
09519 }
09520
09521 if (skylines) {
09522 line = cpl_vector_get_data(skylines);
09523 nlines = cpl_vector_get_size(skylines);
09524 }
09525 else {
09526 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
09527 "given: using internal list of reference sky lines");
09528 if (highres) {
09529 line = default_lines_hi;
09530 nlines = sizeof(default_lines_hi) / sizeof(double);
09531 }
09532 else {
09533 line = default_lines_lo;
09534 nlines = sizeof(default_lines_lo) / sizeof(double);
09535 }
09536 }
09537
09538 if (calibration)
09539 cdata = cpl_image_get_data(calibration);
09540
09541 nx = cpl_image_get_size_x(image);
09542 ny = cpl_image_get_size_y(image);
09543
09544 nslits = cpl_table_get_nrow(slits);
09545 slit_id = cpl_table_get_data_int(slits, "slit_id");
09546 position = cpl_table_get_data_int(slits, "position");
09547 length = cpl_table_get_data_int(slits, "length");
09548
09549
09550
09551
09552
09553
09554 nrows = 0;
09555 for (i = 0; i < nlines; i++)
09556 if (line[i] > firstLambda && line[i] < lastLambda)
09557 nrows++;
09558
09559 offsets = cpl_table_new(nrows);
09560 cpl_table_new_column(offsets, "wave", CPL_TYPE_DOUBLE);
09561 cpl_table_set_column_unit(offsets, "wave", "Angstrom");
09562
09563 nrows = 0;
09564 for (i = 0; i < nlines; i++) {
09565 if (line[i] > firstLambda && line[i] < lastLambda) {
09566 cpl_table_set_double(offsets, "wave", nrows, line[i]);
09567 nrows++;
09568 }
09569 }
09570
09571
09572
09573
09574
09575 line = cpl_table_get_data_double(offsets, "wave");
09576 nlines = nrows;
09577
09578 idsorder = 0;
09579 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
09580 ++idsorder;
09581 --idsorder;
09582
09583 xlow = 1;
09584 xhig = nx;
09585 for (i = 0; i < nslits; i++) {
09586
09587 if (length[i] == 0)
09588 continue;
09589
09590 snprintf(offname, MAX_COLNAME, "offset%d", slit_id[i]);
09591 cpl_table_new_column(offsets, offname, CPL_TYPE_DOUBLE);
09592
09593
09594
09595
09596
09597
09598
09599
09600
09601
09602
09603 ylow = position[i] + 1;
09604 yhig = ylow + length[i] - 1;
09605
09606 exslit = cpl_image_extract(image, xlow, ylow, xhig, yhig);
09607 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
09608 sdata = cpl_image_get_data(sky);
09609
09610 cpl_image_delete(exslit);
09611
09612
09613
09614
09615
09616
09617 ylow--;
09618
09619
09620
09621
09622
09623
09624
09625 dummy = cpl_table_new(yhig - ylow);
09626 for (j = 0; j < nlines; j++) {
09627 snprintf(name, MAX_COLNAME, "%d", j);
09628 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
09629 }
09630
09631 for (j = ylow; j < yhig; j++) {
09632
09633
09634
09635
09636
09637 missing = 0;
09638 ids = cpl_polynomial_new(1);
09639 for (k = 0; k <= idsorder; k++) {
09640 c = cpl_table_get_double(idscoeff, clab[k], j, &null);
09641 if (null) {
09642 cpl_polynomial_delete(ids);
09643 missing = 1;
09644 break;
09645 }
09646 cpl_polynomial_set_coeff(ids, &k, c);
09647 }
09648 if (missing)
09649 continue;
09650
09651 for (k = 0; k < nlines; k++) {
09652 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
09653 startPos = expPos - sradius;
09654 endPos = startPos + window;
09655 if (startPos < 0 || endPos >= nx)
09656 continue;
09657
09658 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
09659 pos += startPos;
09660 offset = pos - expPos;
09661 snprintf(name, MAX_COLNAME, "%d", k);
09662 cpl_table_set_double(dummy, name, j - ylow, offset);
09663 }
09664 }
09665
09666 cpl_polynomial_delete(ids);
09667 }
09668
09669 cpl_image_delete(sky);
09670
09671 for (j = 0; j < nlines; j++) {
09672 snprintf(name, MAX_COLNAME, "%d", j);
09673 if (cpl_table_has_valid(dummy, name)) {
09674 offset = cpl_table_get_column_median(dummy, name);
09675 cpl_table_set_double(offsets, offname, j, offset);
09676 }
09677 }
09678
09679 cpl_table_delete(dummy);
09680
09681 }
09682
09683
09684
09685
09686
09687
09688
09689
09690 for (i = 0; i < nslits; i++) {
09691
09692 if (length[i] == 0)
09693 continue;
09694
09695 snprintf(offname, MAX_COLNAME, "offset%d", slit_id[i]);
09696
09697
09698
09699
09700
09701
09702 dummy = cpl_table_new(nlines);
09703 cpl_table_duplicate_column(dummy, "wave", offsets, "wave");
09704 cpl_table_duplicate_column(dummy, "offset", offsets, offname);
09705
09706 npoints = nlines - cpl_table_count_invalid(dummy, "offset");
09707 if (npoints == 0) {
09708 cpl_msg_warning(func, "No sky lines alignment was possible "
09709 "for slit ID=%d: no sky line found", slit_id[i]);
09710 cpl_table_delete(dummy);
09711 continue;
09712 }
09713
09714 uorder = order;
09715 if (npoints <= uorder) {
09716 uorder = npoints - 1;
09717 if (uorder) {
09718 cpl_msg_warning(func, "Just %d sky lines detected for slit "
09719 "ID=%d, while a polynomial order %d was "
09720 "requested. Using polynomial order %d for "
09721 "this slit!", npoints, slit_id[i], order,
09722 uorder);
09723 }
09724 else {
09725 cpl_msg_warning(func, "Just %d sky lines detected for slit "
09726 "ID=%d, while a polynomial order %d was "
09727 "requested. Computing a median offset for "
09728 "this slit!", npoints, slit_id[i], order);
09729 }
09730 }
09731
09732 cpl_table_erase_invalid(dummy);
09733
09734 if (uorder > 1) {
09735
09736
09737
09738
09739
09740 wave = cpl_vector_wrap(npoints,
09741 cpl_table_get_data_double(dummy, "wave"));
09742 offs = cpl_vector_wrap(npoints,
09743 cpl_table_get_data_double(dummy, "offset"));
09744
09745
09746
09747
09748
09749 cpl_vector_subtract_scalar(wave, refwave);
09750
09751 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
09752
09753 rms = sqrt(rms * (uorder + 1) / npoints);
09754
09755 cpl_vector_unwrap(wave);
09756 cpl_vector_unwrap(offs);
09757 cpl_table_delete(dummy);
09758
09759
09760
09761
09762
09763
09764 ylow = position[i];
09765 yhig = ylow + length[i];
09766
09767 for (j = 0; j <= uorder; j++) {
09768 data = cpl_table_get_data_double(idscoeff, clab[j]);
09769 c = cpl_polynomial_get_coeff(polycorr, &j);
09770 for (k = ylow; k < yhig; k++)
09771 data[k] += c;
09772 }
09773
09774 data = cpl_table_get_data_double(idscoeff, "error");
09775 for (k = ylow; k < yhig; k++)
09776 data[k] = sqrt(data[k]*data[k] + rms*rms);
09777
09778 idata = cpl_table_get_data_int(idscoeff, "nlines");
09779 for (k = ylow; k < yhig; k++)
09780 idata[k] = npoints;
09781
09782
09783
09784
09785
09786
09787 if (calibration) {
09788 for (j = ylow; j < yhig; j++) {
09789 for (k = 1; k < nx; k++) {
09790 lambda1 = cdata[k - 1 + j*nx];
09791 lambda2 = cdata[k + j*nx];
09792 if (lambda1 < 1.0 || lambda2 < 1.0)
09793 continue;
09794 offset = cpl_polynomial_eval_1d(polycorr,
09795 lambda1-refwave, NULL);
09796 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
09797 }
09798 }
09799 }
09800
09801 cpl_polynomial_delete(polycorr);
09802 }
09803 else if (uorder == 1) {
09804
09805
09806
09807
09808
09809 double q, m;
09810 cpl_bivector *list;
09811
09812
09813 wave = cpl_vector_wrap(npoints,
09814 cpl_table_get_data_double(dummy, "wave"));
09815 offs = cpl_vector_wrap(npoints,
09816 cpl_table_get_data_double(dummy, "offset"));
09817
09818 list = cpl_bivector_wrap_vectors(wave, offs);
09819
09820
09821
09822
09823
09824 cpl_vector_subtract_scalar(wave, refwave);
09825
09826 robustLinearFit(list, &q, &m, &rms);
09827
09828 rms = sqrt(rms * (uorder + 1) / npoints);
09829
09830 cpl_bivector_unwrap_vectors(list);
09831 cpl_vector_unwrap(wave);
09832 cpl_vector_unwrap(offs);
09833 cpl_table_delete(dummy);
09834
09835
09836
09837
09838
09839
09840 ylow = position[i];
09841 yhig = ylow + length[i];
09842
09843 for (j = 0; j <= uorder; j++) {
09844 data = cpl_table_get_data_double(idscoeff, clab[j]);
09845 if (j)
09846 c = m;
09847 else
09848 c = q;
09849 for (k = ylow; k < yhig; k++)
09850 data[k] += c;
09851 }
09852
09853 data = cpl_table_get_data_double(idscoeff, "error");
09854 for (k = ylow; k < yhig; k++)
09855 data[k] = sqrt(data[k]*data[k] + rms*rms);
09856
09857 idata = cpl_table_get_data_int(idscoeff, "nlines");
09858 for (k = ylow; k < yhig; k++)
09859 idata[k] = npoints;
09860
09861
09862
09863
09864
09865
09866 if (calibration) {
09867 for (j = ylow; j < yhig; j++) {
09868 for (k = 1; k < nx; k++) {
09869 lambda1 = cdata[k - 1 + j*nx];
09870 lambda2 = cdata[k + j*nx];
09871 if (lambda1 < 1.0 || lambda2 < 1.0)
09872 continue;
09873 offset = q + m*(lambda1-refwave);
09874 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
09875 }
09876 }
09877 }
09878 }
09879 else {
09880
09881
09882
09883
09884
09885 offs = cpl_vector_wrap(npoints,
09886 cpl_table_get_data_double(dummy, "offset"));
09887
09888 offset = cpl_vector_get_median_const(offs);
09889
09890 if (npoints > 1)
09891 rms = cpl_table_get_column_stdev(dummy, "offset");
09892 else
09893 rms = 0.0;
09894
09895 rms /= sqrt(npoints);
09896
09897 cpl_vector_unwrap(offs);
09898 cpl_table_delete(dummy);
09899
09900
09901
09902
09903
09904
09905 ylow = position[i];
09906 yhig = ylow + length[i];
09907
09908 data = cpl_table_get_data_double(idscoeff, clab[0]);
09909 for (k = ylow; k < yhig; k++)
09910 data[k] += offset;
09911
09912 data = cpl_table_get_data_double(idscoeff, "error");
09913 for (k = ylow; k < yhig; k++)
09914 data[k] = sqrt(data[k]*data[k] + rms*rms);
09915
09916 idata = cpl_table_get_data_int(idscoeff, "nlines");
09917 for (k = ylow; k < yhig; k++)
09918 idata[k] = npoints;
09919
09920
09921
09922
09923
09924
09925
09926 if (calibration) {
09927 for (j = ylow; j < yhig; j++) {
09928 for (k = 1; k < nx; k++) {
09929 lambda1 = cdata[k - 1 + j*nx];
09930 lambda2 = cdata[k + j*nx];
09931 if (lambda1 < 1.0 || lambda2 < 1.0)
09932 continue;
09933 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
09934 }
09935 }
09936 }
09937 }
09938 }
09939
09940 return offsets;
09941
09942 }
09943
09944
10006 cpl_table *mos_wavelength_align_lss(cpl_image *image, double refwave,
10007 double firstLambda, double lastLambda,
10008 cpl_table *idscoeff, cpl_vector *skylines,
10009 int highres, int order,
10010 cpl_image *calibration, int sradius)
10011 {
10012 const char *func = "mos_wavelength_align_lss";
10013
10014 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10015
10016 double *line;
10017 double *data;
10018 double *wdata;
10019 double *odata;
10020 double expPos, offset;
10021 double c;
10022 double lambda1, lambda2;
10023 double rms;
10024 float pos;
10025 float *sdata;
10026 float *cdata;
10027 int *idata;
10028 int startPos, endPos;
10029 int window = 2*sradius + 1;
10030 int nlines;
10031 int npoints;
10032 int nrows;
10033 int nx, ny;
10034 int idsorder, uorder;
10035 int missing;
10036 int i, j, k;
10037
10038 char name[MAX_COLNAME];
10039 char fname[MAX_COLNAME];
10040
10041 cpl_polynomial *ids;
10042 cpl_polynomial *polycorr;
10043 cpl_table *offsets;
10044 cpl_table *fittable;
10045 cpl_table *dummy;
10046 cpl_vector *wave;
10047 cpl_vector *offs;
10048 cpl_vector *row;
10049
10050
10051 if (idscoeff == NULL) {
10052 cpl_msg_error(func, "An IDS coeff table must be given");
10053 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10054 return NULL;
10055 }
10056
10057 if (image == NULL) {
10058 cpl_msg_error(func, "A scientific spectral image must be given");
10059 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10060 return NULL;
10061 }
10062
10063 if (skylines) {
10064 line = cpl_vector_get_data(skylines);
10065 nlines = cpl_vector_get_size(skylines);
10066 }
10067 else {
10068 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
10069 "given: using internal list of reference sky lines");
10070 if (highres) {
10071 line = default_lines_hi;
10072 nlines = sizeof(default_lines_hi) / sizeof(double);
10073 }
10074 else {
10075 line = default_lines_lo;
10076 nlines = sizeof(default_lines_lo) / sizeof(double);
10077 }
10078 }
10079
10080 if (calibration)
10081 cdata = cpl_image_get_data(calibration);
10082
10083 nx = cpl_image_get_size_x(image);
10084 ny = cpl_image_get_size_y(image);
10085
10086 sdata = cpl_image_get_data(image);
10087
10088 if (ny != cpl_table_get_nrow(idscoeff)) {
10089 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
10090 return NULL;
10091 }
10092
10093
10094
10095
10096
10097
10098
10099
10100
10101
10102 nrows = 0;
10103 for (i = 0; i < nlines; i++)
10104 if (line[i] > firstLambda && line[i] < lastLambda)
10105 nrows++;
10106
10107 offsets = cpl_table_new(nrows);
10108 cpl_table_new_column(offsets, "wave", CPL_TYPE_DOUBLE);
10109 cpl_table_set_column_unit(offsets, "wave", "Angstrom");
10110
10111 nrows = 0;
10112 for (i = 0; i < nlines; i++) {
10113 if (line[i] > firstLambda && line[i] < lastLambda) {
10114 cpl_table_set_double(offsets, "wave", nrows, line[i]);
10115 nrows++;
10116 }
10117 }
10118
10119
10120
10121
10122
10123 line = cpl_table_get_data_double(offsets, "wave");
10124 nlines = nrows;
10125
10126 idsorder = 0;
10127 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
10128 ++idsorder;
10129 --idsorder;
10130
10131
10132
10133
10134
10135
10136
10137 dummy = cpl_table_new(ny);
10138 for (j = 0; j < nlines; j++) {
10139 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
10140 snprintf(fname, MAX_COLNAME, "fit_%d", (int)line[j]);
10141 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
10142 cpl_table_new_column(dummy, fname, CPL_TYPE_DOUBLE);
10143 }
10144
10145 for (j = 0; j < ny; j++, sdata += nx) {
10146
10147
10148
10149
10150
10151 missing = 0;
10152 ids = cpl_polynomial_new(1);
10153 for (k = 0; k <= idsorder; k++) {
10154 c = cpl_table_get_double(idscoeff, clab[k], j, &missing);
10155 if (missing) {
10156 cpl_polynomial_delete(ids);
10157 break;
10158 }
10159 cpl_polynomial_set_coeff(ids, &k, c);
10160 }
10161 if (missing)
10162 continue;
10163
10164 for (k = 0; k < nlines; k++) {
10165 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
10166 startPos = expPos - sradius;
10167 endPos = startPos + window;
10168 if (startPos < 0 || endPos >= nx)
10169 continue;
10170
10171 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
10172 pos += startPos;
10173 offset = pos - expPos;
10174 snprintf(name, MAX_COLNAME, "off_%d", (int)line[k]);
10175 cpl_table_set_double(dummy, name, j, offset);
10176 }
10177 }
10178
10179 cpl_polynomial_delete(ids);
10180 }
10181
10182
10183
10184
10185
10186
10187
10188 for (j = 0; j < nlines; j++) {
10189 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
10190 snprintf(fname, MAX_COLNAME, "fit_%d", (int)line[j]);
10191 if (cpl_table_has_valid(dummy, name)) {
10192
10193
10194
10195
10196
10197
10198 double q, m;
10199 cpl_bivector *list;
10200
10201 fittable = cpl_table_new(ny);
10202 cpl_table_new_column(fittable, "row", CPL_TYPE_DOUBLE);
10203 cpl_table_set_column_unit(fittable, "row", "pixel");
10204 for (k = 0; k < ny; k++)
10205 cpl_table_set_double(fittable, "row", k, k);
10206 cpl_table_duplicate_column(fittable, "offset", dummy, name);
10207 npoints = ny - cpl_table_count_invalid(fittable, "offset");
10208 cpl_table_erase_invalid(fittable);
10209 row = cpl_vector_wrap(npoints,
10210 cpl_table_get_data_double(fittable, "row"));
10211 offs = cpl_vector_wrap(npoints,
10212 cpl_table_get_data_double(fittable, "offset"));
10213 list = cpl_bivector_wrap_vectors(row, offs);
10214 robustLinearFit(list, &q, &m, &rms);
10215 cpl_bivector_unwrap_vectors(list);
10216 cpl_vector_unwrap(row);
10217 cpl_vector_unwrap(offs);
10218 cpl_table_delete(fittable);
10219 for (k = 0; k < ny; k++)
10220 cpl_table_set_double(dummy, fname, k, q + m*k);
10221 }
10222 }
10223
10224
10225
10226
10227
10228
10229
10230
10231
10232
10233 for (i = 0; i < ny; i++) {
10234
10235 if (!cpl_table_is_valid(idscoeff, clab[0], i))
10236 continue;
10237
10238 npoints = 0;
10239 for (j = 0; j < nlines; j++) {
10240 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
10241 if (cpl_table_is_valid(dummy, name, i))
10242 npoints++;
10243 }
10244
10245 if (npoints == 0)
10246 continue;
10247
10248 uorder = order;
10249 if (npoints <= uorder)
10250 uorder = npoints - 1;
10251
10252 if (uorder > 1) {
10253
10254
10255
10256
10257
10258 wave = cpl_vector_new(npoints);
10259 wdata = cpl_vector_get_data(wave);
10260 offs = cpl_vector_new(npoints);
10261 odata = cpl_vector_get_data(offs);
10262
10263 npoints = 0;
10264 for (j = 0; j < nlines; j++) {
10265 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
10266 if (cpl_table_is_valid(dummy, name, i)) {
10267 wdata[npoints] = line[j] - refwave;
10268 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10269 npoints++;
10270 }
10271 }
10272
10273 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
10274
10275 rms = sqrt(rms * (uorder + 1) / npoints);
10276
10277 cpl_vector_delete(wave);
10278 cpl_vector_delete(offs);
10279
10280
10281
10282
10283
10284
10285 for (j = 0; j <= uorder; j++) {
10286 data = cpl_table_get_data_double(idscoeff, clab[j]);
10287 c = cpl_polynomial_get_coeff(polycorr, &j);
10288 data[i] += c;
10289 }
10290
10291 data = cpl_table_get_data_double(idscoeff, "error");
10292 data[i] = sqrt(data[i]*data[i] + rms*rms);
10293
10294 idata = cpl_table_get_data_int(idscoeff, "nlines");
10295 idata[i] = npoints;
10296
10297
10298
10299
10300
10301
10302 if (calibration) {
10303 for (k = 1; k < nx; k++) {
10304 lambda1 = cdata[k - 1 + i*nx];
10305 lambda2 = cdata[k + i*nx];
10306 if (lambda1 < 1.0 || lambda2 < 1.0)
10307 continue;
10308 offset = cpl_polynomial_eval_1d(polycorr,
10309 lambda1-refwave, NULL);
10310 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10311 }
10312 }
10313
10314 cpl_polynomial_delete(polycorr);
10315
10316 }
10317 else if (uorder == 1) {
10318
10319
10320
10321
10322
10323 cpl_bivector *list;
10324 double q, m;
10325
10326 wave = cpl_vector_new(npoints);
10327 wdata = cpl_vector_get_data(wave);
10328 offs = cpl_vector_new(npoints);
10329 odata = cpl_vector_get_data(offs);
10330
10331 npoints = 0;
10332 for (j = 0; j < nlines; j++) {
10333 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
10334 if (cpl_table_is_valid(dummy, name, i)) {
10335 wdata[npoints] = line[j] - refwave;
10336 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10337 npoints++;
10338 }
10339 }
10340
10341 list = cpl_bivector_wrap_vectors(wave, offs);
10342 robustLinearFit(list, &q, &m, &rms);
10343
10344 rms = sqrt(rms * (uorder + 1) / npoints);
10345
10346 cpl_bivector_unwrap_vectors(list);
10347 cpl_vector_delete(wave);
10348 cpl_vector_delete(offs);
10349
10350
10351
10352
10353
10354
10355 for (j = 0; j <= uorder; j++) {
10356 data = cpl_table_get_data_double(idscoeff, clab[j]);
10357 if (j)
10358 c = m;
10359 else
10360 c = q;
10361 data[i] += c;
10362 }
10363
10364 data = cpl_table_get_data_double(idscoeff, "error");
10365 data[i] = sqrt(data[i]*data[i] + rms*rms);
10366
10367 idata = cpl_table_get_data_int(idscoeff, "nlines");
10368 idata[i] = npoints;
10369
10370
10371
10372
10373
10374
10375 if (calibration) {
10376 for (k = 1; k < nx; k++) {
10377 lambda1 = cdata[k - 1 + i*nx];
10378 lambda2 = cdata[k + i*nx];
10379 if (lambda1 < 1.0 || lambda2 < 1.0)
10380 continue;
10381 offset = q + m*(lambda1-refwave);
10382 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10383 }
10384 }
10385 }
10386 else {
10387
10388
10389
10390
10391
10392 offs = cpl_vector_new(npoints);
10393 odata = cpl_vector_get_data(offs);
10394
10395 npoints = 0;
10396 for (j = 0; j < nlines; j++) {
10397 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
10398 if (cpl_table_is_valid(dummy, name, i)) {
10399 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10400 npoints++;
10401 }
10402 }
10403
10404 offset = cpl_vector_get_median_const(offs);
10405
10406 if (npoints > 1) {
10407 rms = cpl_vector_get_stdev(offs);
10408 }
10409 else if (npoints == 1) {
10410 snprintf(name, MAX_COLNAME, "off_%d", (int)line[0]);
10411 if (cpl_table_has_valid(dummy, name)) {
10412 rms = cpl_table_get_column_stdev(dummy, name);
10413 rms /= sqrt(ny - cpl_table_count_invalid(dummy, name));
10414 }
10415 else {
10416 rms = 0.0;
10417 }
10418 }
10419 else {
10420 rms = 0.0;
10421 }
10422
10423 rms /= sqrt(npoints);
10424
10425 cpl_vector_delete(offs);
10426
10427
10428
10429
10430
10431
10432 data = cpl_table_get_data_double(idscoeff, clab[0]);
10433 data[i] += offset;
10434
10435 data = cpl_table_get_data_double(idscoeff, "error");
10436 data[i] = sqrt(data[i]*data[i] + rms*rms);
10437
10438 idata = cpl_table_get_data_int(idscoeff, "nlines");
10439 idata[i] = npoints;
10440
10441
10442
10443
10444
10445
10446
10447 if (calibration) {
10448 for (k = 1; k < nx; k++) {
10449 lambda1 = cdata[k - 1 + i*nx];
10450 lambda2 = cdata[k + i*nx];
10451 if (lambda1 < 1.0 || lambda2 < 1.0)
10452 continue;
10453 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10454 }
10455 }
10456 }
10457 }
10458
10459 missing = 1;
10460 for (j = 0; j < nlines; j++) {
10461 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
10462 if (cpl_table_has_valid(dummy, name)) {
10463 missing = 0;
10464 offset = cpl_table_get_column_median(dummy, name);
10465 cpl_msg_info(func, "Median offset for %.3f: %.3f pixel",
10466 line[j], offset);
10467 }
10468 else {
10469 cpl_msg_info(func,
10470 "Median offset for %.2f: not available", line[j]);
10471 }
10472 }
10473
10474 cpl_table_delete(offsets);
10475
10476 if (missing) {
10477 cpl_table_delete(dummy);
10478 dummy = NULL;
10479 }
10480
10481 return dummy;
10482
10483 }
10484
10485
10513 double mos_distortions_rms(cpl_image *rectified, cpl_vector *lines,
10514 double wavestart, double dispersion, int radius,
10515 int highres)
10516 {
10517
10518 const char *func = "mos_distortions_rms";
10519
10520 int xlen;
10521 int ylen;
10522 int numLines;
10523 int cpix, npix, nzero;
10524 int sp, ep;
10525 int i, j, k;
10526 int npeaks, allPeaks;
10527
10528 float *profile;
10529 float peak, expectPeak, offset;
10530 double lambda;
10531
10532 double average;
10533 double rms, oneRms;
10534
10535 float *sdata;
10536 double *wdata;
10537
10538
10539 xlen = cpl_image_get_size_x(rectified);
10540 ylen = cpl_image_get_size_y(rectified);
10541 sdata = cpl_image_get_data(rectified);
10542
10543 if (lines) {
10544 wdata = cpl_vector_get_data(lines);
10545 numLines = cpl_vector_get_size(lines);
10546 }
10547 else {
10548 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
10549 "given: using internal list of reference sky lines");
10550 if (highres) {
10551 wdata = default_lines_hi;
10552 numLines = sizeof(default_lines_hi) / sizeof(double);
10553 }
10554 else {
10555 wdata = default_lines_lo;
10556 numLines = sizeof(default_lines_lo) / sizeof(double);
10557 }
10558 }
10559
10560 npix = 2 * radius + 1;
10561 profile = cpl_calloc(npix, sizeof(float));
10562
10563 rms = 0.0;
10564 allPeaks = 0;
10565
10566 for (i = 0; i < numLines; i++) {
10567
10568
10569
10570
10571
10572 lambda = wdata[i];
10573 expectPeak = (lambda - wavestart) / dispersion;
10574 cpix = floor(expectPeak + 0.5);
10575
10576
10577
10578
10579
10580 sp = cpix - radius;
10581 ep = cpix + radius;
10582
10583 if (sp < 0 || ep > xlen)
10584 continue;
10585
10586 average = 0.0;
10587 npeaks = 0;
10588 oneRms = 0.0;
10589
10590 for (j = 0; j < ylen; j++) {
10591 nzero = 0;
10592 for (k = 0; k < npix; k++) {
10593 profile[k] = sdata[sp + k + j * xlen];
10594 if (fabs(profile[k]) < 0.0001)
10595 nzero++;
10596 }
10597 if (nzero > 0)
10598 continue;
10599
10600 if (peakPosition(profile, npix, &peak, 1) == 0) {
10601 offset = (sp + peak) - expectPeak;
10602 average += offset;
10603 rms += fabs(offset);
10604 oneRms += fabs(offset);
10605 npeaks++;
10606 allPeaks++;
10607 }
10608 }
10609
10610 if (npeaks)
10611 cpl_msg_info(func, "RMS for %.2f: %.3f pixel (%d points)",
10612 lambda, oneRms / npeaks * 1.25, npeaks);
10613 else
10614 cpl_msg_info(func, "RMS for %.2f: line not available", lambda);
10615 }
10616
10617 cpl_free(profile);
10618
10619 if (allPeaks < 10)
10620 return 0.0;
10621
10622 rms /= allPeaks;
10623 rms *= 1.25;
10624
10625 return rms;
10626
10627 }
10628
10629
10650 cpl_image *mos_map_pixel(cpl_table *idscoeff, double reference,
10651 double blue, double red, double dispersion, int trend)
10652 {
10653 const char *func = "mos_map_pixel";
10654
10655 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10656
10657
10658 cpl_polynomial *ids;
10659 cpl_image *map;
10660 float *mdata;
10661 double lambda;
10662 double c;
10663 int order;
10664 int xsize, ysize;
10665 int missing;
10666 int i, j, k;
10667
10668
10669 if (idscoeff == NULL) {
10670 cpl_msg_error(func, "An IDS coeff table must be given");
10671 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10672 return NULL;
10673 }
10674
10675 xsize = (red - blue) / dispersion;
10676 ysize = cpl_table_get_nrow(idscoeff);
10677 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
10678 mdata = cpl_image_get_data(map);
10679
10680 order = 0;
10681 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
10682 ++order;
10683 --order;
10684
10685 for (i = 0; i < ysize; i++, mdata += xsize) {
10686
10687 missing = 0;
10688 ids = cpl_polynomial_new(1);
10689 for (k = trend; k <= order; k++) {
10690 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
10691 if (missing) {
10692 cpl_polynomial_delete(ids);
10693 break;
10694 }
10695 cpl_polynomial_set_coeff(ids, &k, c);
10696 }
10697 if (missing)
10698 continue;
10699
10700 for (j = 0; j < xsize; j++) {
10701 lambda = blue + j*dispersion;
10702 mdata[j] = cpl_polynomial_eval_1d(ids, lambda-reference, NULL);
10703 }
10704
10705 cpl_polynomial_delete(ids);
10706 }
10707
10708 return map;
10709
10710 }
10711
10712
10734 cpl_image *mos_map_idscoeff(cpl_table *idscoeff, int xsize, double reference,
10735 double blue, double red)
10736 {
10737 const char *func = "mos_map_idscoeff";
10738
10739 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10740
10741
10742 cpl_polynomial *ids;
10743 cpl_image *map;
10744 float *mdata;
10745 double lambda;
10746 double c;
10747 int order;
10748 int ysize;
10749 int missing;
10750 int i, j, k;
10751
10752
10753 if (idscoeff == NULL) {
10754 cpl_msg_error(func, "An IDS coeff table must be given");
10755 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10756 return NULL;
10757 }
10758
10759 if (xsize < 1) {
10760 cpl_msg_error(func, "Invalid image size");
10761 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10762 return NULL;
10763 }
10764
10765 if (xsize < 20 || xsize > 5000) {
10766 cpl_msg_warning(func, "Do you really have a detector %d pixels long?",
10767 xsize);
10768 }
10769
10770 ysize = cpl_table_get_nrow(idscoeff);
10771 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
10772 mdata = cpl_image_get_data(map);
10773
10774 order = 0;
10775 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
10776 ++order;
10777 --order;
10778
10779 for (i = 0; i < ysize; i++, mdata += xsize) {
10780
10781 missing = 0;
10782 ids = cpl_polynomial_new(1);
10783 for (k = 0; k <= order; k++) {
10784 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
10785 if (missing) {
10786 cpl_polynomial_delete(ids);
10787 break;
10788 }
10789 cpl_polynomial_set_coeff(ids, &k, c);
10790 }
10791 if (missing)
10792 continue;
10793
10794 for (j = 0; j < xsize; j++) {
10795 lambda = mos_eval_dds(ids, blue, red, reference, j);
10796
10797 if (lambda >= blue && lambda <= red) {
10798 mdata[j] = lambda;
10799 }
10800 }
10801
10802 cpl_polynomial_delete(ids);
10803 }
10804
10805 return map;
10806
10807 }
10808
10809
10844 cpl_image *mos_map_wavelengths(cpl_image *spatial, cpl_image *calibration,
10845 cpl_table *slits, cpl_table *polytraces,
10846 double reference, double blue, double red,
10847 double dispersion)
10848 {
10849 const char *func = "mos_map_wavelengths";
10850
10851 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10852
10853 cpl_polynomial *polytop;
10854 cpl_polynomial *polybot;
10855 cpl_image *remapped;
10856 float *data;
10857 float *wdata;
10858 float *sdata;
10859 float *xdata;
10860 double vtop, vbot, value;
10861 double top, bot;
10862 double coeff;
10863 double ytop, ybot;
10864 double ypos;
10865 double fvalue;
10866 int ivalue;
10867 int yint, ysize, yprev;
10868 int nslits;
10869 int npseudo;
10870 int *slit_id;
10871 int *position;
10872 int *length;
10873 int nx, ny;
10874 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
10875 int missing_top, missing_bot;
10876 int null;
10877 int order;
10878 int i, j, k;
10879
10880
10881 if (spatial == NULL || calibration == NULL ||
10882 slits == NULL || polytraces == NULL) {
10883 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10884 return NULL;
10885 }
10886
10887 if (dispersion <= 0.0) {
10888 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10889 return NULL;
10890 }
10891
10892 if (red - blue < dispersion) {
10893 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
10894 return NULL;
10895 }
10896
10897 nx = cpl_image_get_size_x(spatial);
10898 ny = cpl_image_get_size_y(spatial);
10899 ysize = cpl_image_get_size_y(calibration);
10900 remapped = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
10901 data = cpl_image_get_data(remapped);
10902 sdata = cpl_image_get_data(spatial);
10903 wdata = cpl_image_get_data(calibration);
10904
10905 nslits = cpl_table_get_nrow(slits);
10906 slit_id = cpl_table_get_data_int(slits, "slit_id");
10907 order = cpl_table_get_ncol(polytraces) - 2;
10908 position = cpl_table_get_data_int(slits, "position");
10909 length = cpl_table_get_data_int(slits, "length");
10910
10911
10912
10913
10914
10915
10916 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
10917 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
10918
10919 for (i = 0; i < nslits; i++) {
10920
10921 if (length[i] == 0)
10922 continue;
10923
10924
10925
10926
10927
10928
10929
10930
10931
10932
10933
10934
10935 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
10936
10937 start_pixel = refpixel - pixel_below;
10938 if (start_pixel < 0)
10939 start_pixel = 0;
10940
10941 end_pixel = refpixel + pixel_above;
10942 if (end_pixel > nx)
10943 end_pixel = nx;
10944
10945
10946
10947
10948
10949
10950 missing_top = 0;
10951 polytop = cpl_polynomial_new(1);
10952 for (k = 0; k <= order; k++) {
10953 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
10954 if (null) {
10955 cpl_polynomial_delete(polytop);
10956 missing_top = 1;
10957 break;
10958 }
10959 cpl_polynomial_set_coeff(polytop, &k, coeff);
10960 }
10961
10962 missing_bot = 0;
10963 polybot = cpl_polynomial_new(1);
10964 for (k = 0; k <= order; k++) {
10965 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
10966 if (null) {
10967 cpl_polynomial_delete(polybot);
10968 missing_bot = 1;
10969 break;
10970 }
10971 cpl_polynomial_set_coeff(polybot, &k, coeff);
10972 }
10973
10974 if (missing_top && missing_bot) {
10975 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
10976 slit_id[i]);
10977 continue;
10978 }
10979
10980
10981
10982
10983
10984
10985
10986 if (missing_top) {
10987 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
10988 "the spectral curvature of the lower edge "
10989 "is used instead.", slit_id[i]);
10990 polytop = cpl_polynomial_duplicate(polybot);
10991 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
10992 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
10993 k = 0;
10994 coeff = cpl_polynomial_get_coeff(polybot, &k);
10995 coeff += ytop - ybot;
10996 cpl_polynomial_set_coeff(polytop, &k, coeff);
10997 }
10998
10999 if (missing_bot) {
11000 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
11001 "the spectral curvature of the upper edge "
11002 "is used instead.", slit_id[i]);
11003 polybot = cpl_polynomial_duplicate(polytop);
11004 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
11005 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
11006 k = 0;
11007 coeff = cpl_polynomial_get_coeff(polytop, &k);
11008 coeff -= ytop - ybot;
11009 cpl_polynomial_set_coeff(polybot, &k, coeff);
11010 }
11011
11012
11013
11014
11015
11016
11017
11018
11019 xdata = wdata + nx*position[i];
11020 npseudo = length[i] - 1;
11021
11022
11023
11024
11025
11026 for (j = start_pixel; j < end_pixel; j++) {
11027 top = cpl_polynomial_eval_1d(polytop, j, NULL);
11028 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
11029 for (k = 0; k <= npseudo; k++) {
11030 ypos = top - k*(top-bot)/npseudo;
11031 yint = ypos;
11032
11033
11034
11035
11036
11037
11038
11039
11040 if (yint < 0 || yint >= ny-1) {
11041 yprev = yint;
11042 continue;
11043 }
11044
11045 value = sdata[j + nx*yint];
11046 ivalue = value;
11047 fvalue = value - ivalue;
11048 if (ivalue < npseudo && ivalue >= 0) {
11049 vtop = xdata[j + nx*(npseudo-ivalue)];
11050 vbot = xdata[j + nx*(npseudo-ivalue-1)];
11051 if (vtop < 1.0) {
11052 if (vbot < 1.0) {
11053 value = 0.0;
11054 }
11055 else {
11056 value = vbot;
11057 }
11058 }
11059 else if (vbot < 1.0) {
11060 if (k)
11061 value = vtop;
11062 else
11063 value = 0.0;
11064 }
11065 else if (fabs(vbot-vtop) > 10*dispersion) {
11066 value = 0.0;
11067 }
11068 else {
11069 value = vtop*(1-fvalue) + vbot*fvalue;
11070 }
11071 data[j + nx*yint] = value;
11072
11073 if (k) {
11074
11075
11076
11077
11078
11079
11080
11081 if (yprev - yint > 1) {
11082 value = sdata[j + nx*(yint+1)];
11083 ivalue = value;
11084 fvalue = value - ivalue;
11085 if (ivalue < npseudo && ivalue >= 0) {
11086 vtop = xdata[j + nx*(npseudo-ivalue)];
11087 vbot = xdata[j + nx*(npseudo-ivalue-1)];
11088 if (vtop < 1.0) {
11089 if (vbot < 1.0) {
11090 value = data[j + nx*(yint+1)];
11091 }
11092 else {
11093 value = vbot;
11094 }
11095 }
11096 else if (vbot < 1.0) {
11097 value = vtop;
11098 }
11099 else if (fabs(vbot-vtop) > 2*dispersion) {
11100 value = vtop;
11101 }
11102 else {
11103 value = vtop*(1-fvalue) + vbot*fvalue;
11104 }
11105 data[j + nx*(yint+1)] = value;
11106 }
11107 }
11108 }
11109 }
11110 yprev = yint;
11111 }
11112 }
11113 cpl_polynomial_delete(polytop);
11114 cpl_polynomial_delete(polybot);
11115 }
11116
11117 return remapped;
11118 }
11119
11193 cpl_image *mos_map_spectrum(cpl_image *spectra, cpl_image *wavecalib,
11194 cpl_image *spatial, cpl_table *slits,
11195 cpl_table *polytraces, double reference,
11196 double blue, double red, double dispersion,
11197 int flux)
11198 {
11199 const char *func = "mos_map_spectrum";
11200
11201 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
11202
11203 cpl_polynomial *polytop;
11204 cpl_polynomial *polybot;
11205 cpl_image *remapped;
11206 cpl_image **exslit;
11207 float *data;
11208 float *wdata;
11209 float *sdata;
11210 float *xdata;
11211 double lambda00, lambda01, lambda10, lambda11, lambda;
11212 double space00, space01, space10, space11, space;
11213 double value00, value01, value10, value11, value0, value1, value;
11214 double dL, dS;
11215 double top, bot;
11216 double coeff;
11217 double ytop, ybot;
11218 double xfrac, yfrac;
11219 int yint, ysize;
11220 int itop, ibot;
11221 int shift;
11222 int L, S;
11223 int nslits;
11224 int npseudo;
11225 int *slit_id;
11226 int *position;
11227 int *length;
11228 int nx, ny;
11229 int x, y;
11230 int nlambda;
11231 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
11232 int missing_top, missing_bot;
11233 int null;
11234 int order;
11235 int i, k;
11236
11237
11238 flux += flux;
11239
11240 if (spectra == NULL || spatial == NULL || wavecalib == NULL ||
11241 slits == NULL || polytraces == NULL) {
11242 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11243 return NULL;
11244 }
11245
11246 if (dispersion <= 0.0) {
11247 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11248 return NULL;
11249 }
11250
11251 if (red - blue < dispersion) {
11252 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11253 return NULL;
11254 }
11255
11256 nx = cpl_image_get_size_x(spectra);
11257 ny = cpl_image_get_size_y(spectra);
11258
11259 if (nx != cpl_image_get_size_x(spatial) ||
11260 ny != cpl_image_get_size_y(spatial) ||
11261 nx != cpl_image_get_size_x(wavecalib) ||
11262 ny != cpl_image_get_size_y(wavecalib)) {
11263 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
11264 return NULL;
11265 }
11266
11267 nlambda = STRETCH_FACTOR * (red - blue) / dispersion;
11268 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
11269 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
11270
11271 data = cpl_image_get_data(spectra);
11272 sdata = cpl_image_get_data(spatial);
11273 wdata = cpl_image_get_data(wavecalib);
11274
11275 nslits = cpl_table_get_nrow(slits);
11276 slit_id = cpl_table_get_data_int(slits, "slit_id");
11277 order = cpl_table_get_ncol(polytraces) - 2;
11278 position = cpl_table_get_data_int(slits, "position");
11279 length = cpl_table_get_data_int(slits, "length");
11280
11281 exslit = cpl_calloc(nslits, sizeof(cpl_image *));
11282
11283 for (i = 0; i < nslits; i++) {
11284
11285 if (length == 0)
11286 continue;
11287
11288
11289
11290
11291
11292
11293
11294
11295
11296
11297
11298
11299 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
11300
11301 start_pixel = refpixel - pixel_below;
11302 if (start_pixel < 1)
11303 start_pixel = 1;
11304
11305 end_pixel = refpixel + pixel_above;
11306 if (end_pixel > nx)
11307 end_pixel = nx;
11308
11309
11310
11311
11312
11313
11314 missing_top = 0;
11315 polytop = cpl_polynomial_new(1);
11316 for (k = 0; k <= order; k++) {
11317 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
11318 if (null) {
11319 cpl_polynomial_delete(polytop);
11320 missing_top = 1;
11321 break;
11322 }
11323 cpl_polynomial_set_coeff(polytop, &k, coeff);
11324 }
11325
11326 missing_bot = 0;
11327 polybot = cpl_polynomial_new(1);
11328 for (k = 0; k <= order; k++) {
11329 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
11330 if (null) {
11331 cpl_polynomial_delete(polybot);
11332 missing_bot = 1;
11333 break;
11334 }
11335 cpl_polynomial_set_coeff(polybot, &k, coeff);
11336 }
11337
11338 if (missing_top && missing_bot) {
11339 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
11340 slit_id[i]);
11341 continue;
11342 }
11343
11344
11345
11346
11347
11348
11349
11350 if (missing_top) {
11351 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
11352 "the spectral curvature of the lower edge "
11353 "is used instead.", slit_id[i]);
11354 polytop = cpl_polynomial_duplicate(polybot);
11355 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
11356 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
11357 k = 0;
11358 coeff = cpl_polynomial_get_coeff(polybot, &k);
11359 coeff += ytop - ybot;
11360 cpl_polynomial_set_coeff(polytop, &k, coeff);
11361 }
11362
11363 if (missing_bot) {
11364 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
11365 "the spectral curvature of the upper edge "
11366 "is used instead.", slit_id[i]);
11367 polybot = cpl_polynomial_duplicate(polytop);
11368 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
11369 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
11370 k = 0;
11371 coeff = cpl_polynomial_get_coeff(polytop, &k);
11372 coeff -= ytop - ybot;
11373 cpl_polynomial_set_coeff(polybot, &k, coeff);
11374 }
11375
11376
11377
11378
11379
11380 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
11381 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
11382 npseudo = ceil(top-bot) + 1;
11383
11384 if (npseudo < 1) {
11385 cpl_polynomial_delete(polytop);
11386 cpl_polynomial_delete(polybot);
11387 cpl_msg_debug(func, "Slit %d was badly traced: no extraction!",
11388 slit_id[i]);
11389 continue;
11390 }
11391
11392 exslit[i] = cpl_image_new(nlambda, npseudo+1, CPL_TYPE_FLOAT);
11393 xdata = cpl_image_get_data(exslit[i]);
11394
11395
11396
11397
11398
11399 for (x = start_pixel; x < end_pixel; x++) {
11400 top = cpl_polynomial_eval_1d(polytop, x, NULL);
11401 bot = cpl_polynomial_eval_1d(polybot, x, NULL);
11402 itop = top + 1;
11403 ibot = bot;
11404 if (itop < 0)
11405 itop = 0;
11406 if (itop > ny - 1)
11407 itop = ny - 1;
11408 if (ibot < 0)
11409 ibot = 0;
11410 if (ibot > ny - 1)
11411 ibot = ny - 1;
11412 for (y = ibot; y < itop; y++) {
11413 lambda11 = wdata[x + y*nx];
11414 if (lambda11 < 1.0)
11415 continue;
11416 space11 = sdata[x + y*nx];
11417 if (space11 < 0.0)
11418 continue;
11419 lambda01 = wdata[x - 1 + y*nx];
11420 if (lambda01 < 1.0)
11421 continue;
11422 space01 = sdata[x - 1 + y*nx];
11423 if (space01 < 0.0)
11424 continue;
11425
11426 shift = 0;
11427
11428
11429
11430
11431
11432
11433
11434
11435
11436
11437
11438
11439
11440
11441
11442
11443
11444
11445
11446
11447
11448
11449
11450
11451
11452
11453
11454
11455 lambda10 = wdata[x + shift + (y+1)*nx];
11456 if (lambda10 < 1.0)
11457 continue;
11458 space10 = sdata[x + shift + (y+1)*nx];
11459 if (space10 < 0.0)
11460 continue;
11461 lambda00 = wdata[x - 1 + shift + (y+1)*nx];
11462 if (lambda00 < 1.0)
11463 continue;
11464 space00 = sdata[x - 1 + shift + (y+1)*nx];
11465 if (space00 < 0.0)
11466 continue;
11467
11468
11469
11470
11471
11472
11473
11474 dL = lambda11 - lambda01;
11475 dS = space11 - space10;
11476
11477
11478
11479
11480
11481
11482 L = (lambda11 - blue)/dispersion + 0.5;
11483 S = space11 + 0.5;
11484
11485 if (L < 0 || L >= nlambda)
11486 continue;
11487 if (S < 0 || S > npseudo)
11488 continue;
11489
11490
11491
11492
11493
11494 lambda = blue + L*dispersion;
11495 space = S;
11496
11497
11498
11499
11500
11501
11502
11503
11504
11505
11506 xfrac = (lambda11-lambda)/dL;
11507 yfrac = (space11-space)/dS;
11508
11509
11510
11511
11512
11513
11514
11515
11516
11517
11518 value11 = data[x + y*nx];
11519 value01 = data[x - 1 + y*nx];
11520 value10 = data[x + shift + (y+1)*nx];
11521 value00 = data[x + shift - 1 + (y+1)*nx];
11522
11523
11524
11525
11526
11527 value1 = (1-xfrac)*value11 + xfrac*value01;
11528 value0 = (1-xfrac)*value10 + xfrac*value00;
11529 value = (1-yfrac)*value1 + yfrac*value0;
11530
11531
11532
11533
11534
11535
11536 xdata[L + nlambda*(npseudo-S)] = value;
11537
11538 }
11539 }
11540 cpl_polynomial_delete(polytop);
11541 cpl_polynomial_delete(polybot);
11542 }
11543
11544
11545
11546
11547
11548 ysize = 0;
11549 for (i = 0; i < nslits; i++)
11550 if (exslit[i])
11551 ysize += cpl_image_get_size_y(exslit[i]);
11552
11553 remapped = cpl_image_new(nlambda, ysize, CPL_TYPE_FLOAT);
11554
11555 yint = -1;
11556 for (i = 0; i < nslits; i++) {
11557 if (exslit[i]) {
11558 yint += cpl_image_get_size_y(exslit[i]);
11559 cpl_image_copy(remapped, exslit[i], 1, ysize - yint);
11560 cpl_image_delete(exslit[i]);
11561 cpl_table_set_int(slits, "position", i, ysize - yint - 1);
11562 }
11563 }
11564
11565 cpl_free(exslit);
11566
11567 return remapped;
11568
11569 }
11570
11571
11604 cpl_table *mos_sky_map_super(cpl_image *spectra, cpl_image *wavemap,
11605 double dispersion, double factor, int minpoints,
11606 cpl_image *skymap)
11607 {
11608 const char *func = "mos_sky_map_super";
11609
11610 cpl_vector **vector;
11611 cpl_vector **wvector;
11612 double firstLambda, lastLambda;
11613 double lambda, lambda1, lambda2;
11614 double value, value1, value2;
11615 double frac;
11616 float min, max;
11617 int *count;
11618 int nbin, bin;
11619 int nx, ny, npix;
11620 int first_valid, valid_bins;
11621 int i, j;
11622
11623 cpl_table *sky;
11624 double *sky_spectrum;
11625 double *sky_wave;
11626 float *data;
11627 float *sdata;
11628 float *kdata;
11629
11630
11631 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
11632 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11633 return NULL;
11634 }
11635
11636 if (dispersion <= 0.0) {
11637 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11638 cpl_msg_error(func, "Negative dispersion: %s", cpl_error_get_message());
11639 return NULL;
11640 }
11641
11642 nx = cpl_image_get_size_x(spectra);
11643 ny = cpl_image_get_size_y(spectra);
11644 npix = nx * ny;
11645
11646 if (nx != cpl_image_get_size_x(wavemap) ||
11647 ny != cpl_image_get_size_y(wavemap) ||
11648 nx != cpl_image_get_size_x(skymap) ||
11649 ny != cpl_image_get_size_y(skymap)) {
11650 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
11651 cpl_msg_error(func, "Image sizes: %s", cpl_error_get_message());
11652 return NULL;
11653 }
11654
11655 if (factor < 1.0) {
11656 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11657 cpl_msg_error(func, "Undersampling (%f): %s", factor,
11658 cpl_error_get_message());
11659 return NULL;
11660 }
11661
11662 if (minpoints < 0) {
11663 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11664 cpl_msg_error(func, "Negative threshold: %s", cpl_error_get_message());
11665 return NULL;
11666 }
11667
11668 dispersion /= factor;
11669
11670
11671
11672
11673
11674
11675 data = cpl_image_get_data(wavemap);
11676
11677 for (i = 0; i < npix; i++) {
11678 if (data[i] > 1.0) {
11679 min = max = data[i];
11680 j = i+1;
11681 break;
11682 }
11683 }
11684
11685 for (i = j; i < npix; i++) {
11686 if (data[i] < 1.0)
11687 continue;
11688 if (min > data[i])
11689 min = data[i];
11690 if (max < data[i])
11691 max = data[i];
11692 }
11693
11694 firstLambda = min;
11695 lastLambda = max;
11696
11697
11698
11699
11700
11701
11702 nbin = (lastLambda - firstLambda) / dispersion;
11703
11704
11705
11706
11707
11708
11709
11710
11711 count = cpl_calloc(nbin, sizeof(int));
11712
11713 data = cpl_image_get_data(wavemap);
11714
11715 for (i = 0; i < npix; i++) {
11716 if (data[i] < 1.0)
11717 continue;
11718 bin = (data[i] - firstLambda) / dispersion;
11719 if (bin < nbin)
11720 count[bin]++;
11721 }
11722
11723 valid_bins = 0;
11724 for (i = 0; i < nbin; i++)
11725 if (count[i] >= minpoints)
11726 valid_bins++;
11727
11728 if (valid_bins < nbin/3) {
11729 cpl_msg_warning(func, "Cannot determine a good global sky "
11730 "spectrum from input data");
11731 return NULL;
11732 }
11733
11734
11735
11736
11737
11738
11739
11740
11741
11742 vector = cpl_calloc(nbin, sizeof(cpl_vector *));
11743 wvector = cpl_calloc(nbin, sizeof(cpl_vector *));
11744 for (i = 0; i < nbin; i++) {
11745 if (count[i] >= minpoints) {
11746 vector[i] = cpl_vector_new(count[i]);
11747 wvector[i] = cpl_vector_new(count[i]);
11748 }
11749 count[i] = 0;
11750 }
11751
11752
11753
11754
11755
11756
11757
11758 data = cpl_image_get_data(wavemap);
11759 sdata = cpl_image_get_data(spectra);
11760
11761 for (i = 0; i < npix; i++) {
11762 if (data[i] < 1.0)
11763 continue;
11764 bin = (data[i] - firstLambda) / dispersion;
11765 if (bin < nbin) {
11766 if (vector[bin]) {
11767 cpl_vector_set(vector[bin], count[bin], sdata[i]);
11768 cpl_vector_set(wvector[bin], count[bin], data[i]);
11769 }
11770 count[bin]++;
11771 }
11772 }
11773
11774
11775
11776
11777
11778
11779
11780 sky_spectrum = cpl_calloc(nbin, sizeof(double));
11781 sky_wave = cpl_calloc(nbin, sizeof(double));
11782 for (i = 0; i < nbin; i++) {
11783 if (vector[i]) {
11784 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
11785 sky_wave[i] = cpl_vector_get_median_const(wvector[i]);
11786 cpl_vector_delete(vector[i]);
11787 cpl_vector_delete(wvector[i]);
11788 }
11789 }
11790
11791 cpl_free(vector);
11792 cpl_free(wvector);
11793
11794
11795
11796
11797
11798
11799 for (i = 0; i < nbin; i++) {
11800 if (count[i] >= minpoints) {
11801 first_valid = i;
11802 break;
11803 }
11804 }
11805
11806 for (i = first_valid; i < nbin; i++) {
11807 if (count[i] < minpoints) {
11808 sky_wave[i] = firstLambda + (i+0.5)*dispersion;
11809 for (j = i+1; j < nbin; j++) {
11810 if (count[j] >= minpoints) {
11811 if (sky_wave[j] - sky_wave[i-1] < 0.1) {
11812 sky_spectrum[i] = (sky_spectrum[j] + sky_spectrum[i-1])
11813 / 2;
11814 }
11815 else {
11816 frac = (sky_wave[i] - sky_wave[i-1])
11817 / (sky_wave[j] - sky_wave[i-1]);
11818 sky_spectrum[i] = frac * sky_spectrum[j]
11819 + (1 - frac) * sky_spectrum[i-1];
11820 }
11821 }
11822 }
11823 }
11824 }
11825
11826
11827
11828
11829
11830
11831 sky = cpl_table_new(nbin);
11832 cpl_table_wrap_double(sky, sky_wave, "wavelength");
11833 cpl_table_wrap_double(sky, sky_spectrum, "sky");
11834 cpl_table_wrap_int(sky, count, "npoints");
11835
11836
11837
11838
11839
11840
11841 data = cpl_image_get_data(wavemap);
11842 sdata = cpl_image_get_data(spectra);
11843 kdata = cpl_image_get_data(skymap);
11844
11845 for (i = 0; i < npix; i++) {
11846
11847
11848
11849
11850
11851 lambda = data[i];
11852 if (lambda < 1.0)
11853 continue;
11854 bin = (lambda - firstLambda) / dispersion;
11855 lambda1 = sky_wave[bin];
11856 value1 = sky_spectrum[bin];
11857 if (lambda1 < lambda) {
11858 bin++;
11859 if (bin < nbin) {
11860 lambda2 = sky_wave[bin];
11861 value2 = sky_spectrum[bin];
11862 if (lambda2 - lambda1 < 0.1) {
11863 value = (value1 + value2) / 2;
11864 }
11865 else {
11866 frac = (lambda - lambda1) / (lambda2 - lambda1);
11867 value = frac * value2 + (1 - frac) * value1;
11868 }
11869 }
11870 else {
11871 value = value1;
11872 }
11873 }
11874 else {
11875 if (bin > 0) {
11876 bin--;
11877 lambda2 = lambda1;
11878 value2 = value1;
11879 lambda1 = sky_wave[bin];
11880 value1 = sky_spectrum[bin];
11881 if (lambda2 - lambda1 < 0.1) {
11882 value = (value1 + value2) / 2;
11883 }
11884 else {
11885 frac = (lambda - lambda1) / (lambda2 - lambda1);
11886 value = frac * value2 + (1 - frac) * value1;
11887 }
11888 }
11889 else {
11890 value = value1;
11891 }
11892 }
11893 kdata[i] = value;
11894 }
11895
11896 if (first_valid)
11897 cpl_table_erase_window(sky, 0, first_valid);
11898
11899 return sky;
11900
11901 }
11902
11903
11937 cpl_table *mos_sky_map(cpl_image *spectra, cpl_image *wavemap,
11938 double dispersion, cpl_image *skymap)
11939 {
11940 const char *func = "mos_sky_map";
11941
11942 cpl_vector **vector;
11943 double firstLambda, lastLambda;
11944 double lambda, lambda1, lambda2;
11945 double value, value1, value2;
11946 float min, max;
11947 int *count;
11948 int nbin, bin;
11949 int nx, ny, npix;
11950 int i, j;
11951
11952 cpl_table *sky;
11953 double *sky_spectrum;
11954 float *data;
11955 float *sdata;
11956 float *kdata;
11957 double *wdata;
11958
11959
11960 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
11961 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11962 return NULL;
11963 }
11964
11965 if (dispersion <= 0.0) {
11966 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11967 return NULL;
11968 }
11969
11970 nx = cpl_image_get_size_x(spectra);
11971 ny = cpl_image_get_size_y(spectra);
11972 npix = nx * ny;
11973
11974 if (nx != cpl_image_get_size_x(wavemap) ||
11975 ny != cpl_image_get_size_y(wavemap) ||
11976 nx != cpl_image_get_size_x(skymap) ||
11977 ny != cpl_image_get_size_y(skymap)) {
11978 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
11979 return NULL;
11980 }
11981
11982
11983
11984
11985
11986
11987 data = cpl_image_get_data(wavemap);
11988
11989 for (i = 0; i < npix; i++) {
11990 if (data[i] > 1.0) {
11991 min = max = data[i];
11992 j = i+1;
11993 break;
11994 }
11995 }
11996
11997 for (i = j; i < npix; i++) {
11998 if (data[i] < 1.0)
11999 continue;
12000 if (min > data[i])
12001 min = data[i];
12002 if (max < data[i])
12003 max = data[i];
12004 }
12005
12006 firstLambda = min;
12007 lastLambda = max;
12008
12009
12010
12011
12012
12013
12014 nbin = (lastLambda - firstLambda) / dispersion;
12015
12016
12017
12018
12019
12020
12021
12022
12023 count = cpl_calloc(nbin, sizeof(int));
12024
12025 data = cpl_image_get_data(wavemap);
12026
12027 for (i = 0; i < npix; i++) {
12028 if (data[i] < 1.0)
12029 continue;
12030 bin = (data[i] - firstLambda) / dispersion;
12031 if (bin < nbin)
12032 count[bin]++;
12033 }
12034
12035
12036
12037
12038
12039
12040
12041
12042
12043 vector = cpl_calloc(nbin, sizeof(cpl_vector *));
12044 for (i = 0; i < nbin; i++) {
12045 if (count[i])
12046 vector[i] = cpl_vector_new(count[i]);
12047 else
12048 vector[i] = NULL;
12049 count[i] = 0;
12050 }
12051
12052
12053
12054
12055
12056
12057
12058 data = cpl_image_get_data(wavemap);
12059 sdata = cpl_image_get_data(spectra);
12060
12061 for (i = 0; i < npix; i++) {
12062 if (data[i] < 1.0)
12063 continue;
12064 bin = (data[i] - firstLambda) / dispersion;
12065 if (bin < nbin) {
12066 cpl_vector_set(vector[bin], count[bin], sdata[i]);
12067 count[bin]++;
12068 }
12069 }
12070
12071
12072
12073
12074
12075
12076
12077 sky_spectrum = cpl_calloc(nbin, sizeof(double));
12078 for (i = 0; i < nbin; i++) {
12079 if (vector[i]) {
12080 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
12081 cpl_vector_delete(vector[i]);
12082 }
12083 }
12084
12085 cpl_free(vector);
12086
12087
12088
12089
12090
12091
12092
12093
12094
12095
12096
12097
12098
12099 sky = cpl_table_new(nbin);
12100 cpl_table_new_column(sky, "wavelength", CPL_TYPE_DOUBLE);
12101 cpl_table_set_column_unit(sky, "wavelength", "pixel");
12102 cpl_table_wrap_double(sky, sky_spectrum, "sky");
12103 cpl_table_wrap_int(sky, count, "npoints");
12104 for (i = 0; i < nbin; i++)
12105 cpl_table_set_double(sky, "wavelength", i,
12106 firstLambda + (i+0.5)*dispersion);
12107
12108
12109
12110
12111
12112
12113 data = cpl_image_get_data(wavemap);
12114 sdata = cpl_image_get_data(spectra);
12115 kdata = cpl_image_get_data(skymap);
12116 wdata = cpl_table_get_data_double(sky, "wavelength");
12117
12118 for (i = 0; i < npix; i++) {
12119
12120
12121
12122
12123
12124 lambda = data[i];
12125 if (lambda < 1.0)
12126 continue;
12127 bin = (lambda - firstLambda) / dispersion;
12128 lambda1 = wdata[bin];
12129 value1 = sky_spectrum[bin];
12130 if (lambda1 < lambda) {
12131 bin++;
12132 if (bin < nbin) {
12133 lambda2 = wdata[bin];
12134 value2 = sky_spectrum[bin];
12135 value = ((lambda2 - lambda)*value1
12136 + (lambda - lambda1)*value2) / dispersion;
12137 }
12138 else {
12139 value = value1;
12140 }
12141 }
12142 else {
12143 if (bin > 0) {
12144 bin--;
12145 lambda2 = lambda1;
12146 value2 = value1;
12147 lambda1 = wdata[bin];
12148 value1 = sky_spectrum[bin];
12149 value = ((lambda2 - lambda)*value1
12150 + (lambda - lambda1)*value2)/dispersion;
12151 }
12152 else {
12153 value = value1;
12154 }
12155 }
12156 kdata[i] = value;
12157 }
12158
12159 return sky;
12160
12161 }
12162
12163
12179 cpl_image *mos_sky_local_old(cpl_image *spectra, cpl_table *slits)
12180 {
12181 const char *func = "mos_sky_local_old";
12182
12183 cpl_image *exslit;
12184 cpl_image *sky;
12185 cpl_image *skymap;
12186 float *data;
12187 float *sdata;
12188 int nx, ny;
12189 int xlow, ylow, xhig, yhig;
12190 int nslits;
12191 int *slit_id;
12192 int *position;
12193 int *length;
12194 int i, j, k;
12195
12196
12197 if (spectra == NULL) {
12198 cpl_msg_error(func,
12199 "A scientific rectified spectral image must be given");
12200 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12201 return NULL;
12202 }
12203
12204 if (slits == NULL) {
12205 cpl_msg_error(func, "A slits position table must be given");
12206 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12207 return NULL;
12208 }
12209
12210 nslits = cpl_table_get_nrow(slits);
12211 slit_id = cpl_table_get_data_int(slits, "slit_id");
12212 position = cpl_table_get_data_int(slits, "position");
12213 length = cpl_table_get_data_int(slits, "length");
12214
12215 nx = cpl_image_get_size_x(spectra);
12216 ny = cpl_image_get_size_y(spectra);
12217
12218 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12219
12220 xlow = 1;
12221 xhig = nx;
12222 for (i = 0; i < nslits; i++) {
12223
12224 if (length[i] == 0)
12225 continue;
12226
12227
12228
12229
12230
12231
12232
12233
12234
12235
12236
12237 ylow = position[i] + 1;
12238 yhig = ylow + length[i] - 1;
12239
12240 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
12241 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
12242 cpl_image_delete(exslit);
12243
12244 data = cpl_image_get_data(skymap);
12245 data += nx * position[i];
12246
12247 for (j = 0; j < length[i]; j++) {
12248 sdata = cpl_image_get_data(sky);
12249 for (k = 0; k < nx; k++) {
12250 *data++ = *sdata++;
12251 }
12252 }
12253
12254 cpl_image_delete(sky);
12255 }
12256
12257 return skymap;
12258
12259 }
12260
12261
12281 cpl_image *mos_sky_local(cpl_image *spectra, cpl_table *slits, int order)
12282 {
12283 const char *func = "mos_sky_local";
12284
12285 char name[MAX_COLNAME];
12286
12287 cpl_polynomial *fit;
12288 cpl_vector *points;
12289 cpl_vector *values;
12290 cpl_vector *keep_points;
12291 cpl_vector *keep_values;
12292 cpl_image *exslit;
12293 cpl_image *sky;
12294 cpl_image *subtracted;
12295 cpl_image *profile;
12296 cpl_image *skymap;
12297 cpl_table *objects;
12298 float *data;
12299 float *sdata;
12300 float *xdata;
12301 double *vdata;
12302 double *pdata;
12303 double median;
12304 int nx, ny;
12305 int xlow, ylow, xhig, yhig;
12306 int nslits;
12307 int *slit_id;
12308 int *position;
12309 int *length;
12310 int *is_sky;
12311 int nsky, nbad;
12312 int maxobjects;
12313 int margin = 3;
12314 int radius = 6;
12315 int i, j, k;
12316
12317
12318 if (spectra == NULL) {
12319 cpl_msg_error(func,
12320 "A scientific rectified spectral image must be given");
12321 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12322 return NULL;
12323 }
12324
12325 if (slits == NULL) {
12326 cpl_msg_error(func, "A slits position table must be given");
12327 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12328 return NULL;
12329 }
12330
12331 if (order < 0) {
12332 cpl_msg_error(func, "Invalid fit order");
12333 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12334 return NULL;
12335 }
12336
12337 nslits = cpl_table_get_nrow(slits);
12338 slit_id = cpl_table_get_data_int(slits, "slit_id");
12339 position = cpl_table_get_data_int(slits, "position");
12340 length = cpl_table_get_data_int(slits, "length");
12341
12342 nx = cpl_image_get_size_x(spectra);
12343 ny = cpl_image_get_size_y(spectra);
12344
12345 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12346
12347 xlow = 1;
12348 xhig = nx;
12349 for (i = 0; i < nslits; i++) {
12350
12351 if (length[i] == 0)
12352 continue;
12353
12354
12355
12356
12357
12358
12359
12360
12361
12362
12363
12364 ylow = position[i] + 1;
12365 yhig = ylow + length[i] - 1;
12366
12367 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
12368 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
12369 cpl_image_delete(exslit);
12370
12371 data = cpl_image_get_data(skymap);
12372 data += nx * position[i];
12373
12374 for (j = 0; j < length[i]; j++) {
12375 sdata = cpl_image_get_data(sky);
12376 for (k = 0; k < nx; k++) {
12377 *data++ = *sdata++;
12378 }
12379 }
12380
12381 cpl_image_delete(sky);
12382 }
12383
12384
12385
12386
12387
12388
12389 subtracted = cpl_image_duplicate(spectra);
12390 cpl_image_subtract(subtracted, skymap);
12391 cpl_image_delete(skymap);
12392
12393
12394
12395
12396
12397
12398 objects = cpl_table_duplicate(slits);
12399 profile = mos_detect_objects(subtracted, objects, margin, radius, 0);
12400 cpl_image_delete(profile);
12401 cpl_image_delete(subtracted);
12402
12403
12404
12405
12406
12407
12408
12409 maxobjects = 1;
12410 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
12411 while (cpl_table_has_column(objects, name)) {
12412 maxobjects++;
12413 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
12414 }
12415
12416 is_sky = cpl_calloc(ny, sizeof(int));
12417
12418 for (i = 0; i < nslits; i++) {
12419
12420 if (length[i] == 0)
12421 continue;
12422
12423 ylow = position[i] + margin;
12424 yhig = position[i] + length[i] - margin;
12425
12426 for (j = ylow; j < yhig; j++)
12427 is_sky[j] = 1;
12428
12429 for (j = 1; j < maxobjects; j++) {
12430 snprintf(name, MAX_COLNAME, "object_%d", j);
12431 if (cpl_table_is_valid(objects, name, i)) {
12432 snprintf(name, MAX_COLNAME, "start_%d", j);
12433 ylow = cpl_table_get_int(objects, name, i, NULL);
12434 snprintf(name, MAX_COLNAME, "end_%d", j);
12435 yhig = cpl_table_get_int(objects, name, i, NULL);
12436 for (k = ylow; k <= yhig; k++)
12437 is_sky[k] = 0;
12438 }
12439 }
12440
12441
12442
12443
12444
12445
12446 ylow = position[i] + margin + 1;
12447 yhig = position[i] + length[i] - margin - 1;
12448
12449 for (j = ylow; j < yhig; j++)
12450 if (is_sky[j])
12451 if (is_sky[j-1] == 0 && is_sky[j+1] == 0)
12452 is_sky[j] = 0;
12453
12454 }
12455
12456
12457
12458
12459
12460
12461 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12462
12463 for (i = 0; i < nslits; i++) {
12464
12465 if (length[i] == 0)
12466 continue;
12467
12468 ylow = position[i];
12469 yhig = ylow + length[i];
12470
12471 nsky = 0;
12472 for (j = ylow; j < yhig; j++)
12473 if (is_sky[j])
12474 nsky++;
12475
12476 if (nsky > order + 1) {
12477 if (order) {
12478 points = cpl_vector_new(nsky);
12479 nsky = 0;
12480 for (j = ylow; j < yhig; j++) {
12481 if (is_sky[j]) {
12482 cpl_vector_set(points, nsky, j);
12483 nsky++;
12484 }
12485 }
12486
12487 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
12488 xdata = cpl_image_get_data(exslit);
12489 values = cpl_vector_new(nsky);
12490
12491 for (j = 0; j < nx; j++) {
12492 nsky = 0;
12493 for (k = ylow; k < yhig; k++) {
12494 if (is_sky[k]) {
12495 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
12496 nsky++;
12497 }
12498 }
12499
12500
12501
12502
12503
12504 median = cpl_vector_get_median_const(values);
12505 vdata = cpl_vector_get_data(values);
12506 pdata = cpl_vector_get_data(points);
12507 nbad = 0;
12508 for (k = 0; k < nsky; k++) {
12509 if (fabs(vdata[k] - median) < 100) {
12510 if (nbad) {
12511 vdata[k-nbad] = vdata[k];
12512 pdata[k-nbad] = pdata[k];
12513 }
12514 }
12515 else
12516 nbad++;
12517 }
12518
12519 if (nsky == nbad)
12520 continue;
12521
12522 if (nbad && nsky - nbad > order + 1) {
12523 keep_values = values;
12524 keep_points = points;
12525 values = cpl_vector_wrap(nsky-nbad, vdata);
12526 points = cpl_vector_wrap(nsky-nbad, pdata);
12527 }
12528
12529 if (nsky - nbad > order + 1) {
12530
12531 fit = cpl_polynomial_fit_1d_create(points, values,
12532 order, NULL);
12533
12534 if (fit) {
12535 for (k = ylow; k < yhig; k++) {
12536 xdata[j+(k-ylow)*nx] =
12537 cpl_polynomial_eval_1d(fit, k, NULL);
12538 }
12539
12540 cpl_polynomial_delete(fit);
12541 }
12542 else
12543 cpl_error_reset();
12544 }
12545 else {
12546 for (k = 0; k < nsky; k++) {
12547 xdata[j+k*nx] = median;
12548 }
12549 }
12550
12551 if (nbad && nsky - nbad > order + 1) {
12552 cpl_vector_unwrap(values);
12553 cpl_vector_unwrap(points);
12554 values = keep_values;
12555 points = keep_points;
12556 }
12557
12558 if (nbad) {
12559 nsky = 0;
12560 for (k = ylow; k < yhig; k++) {
12561 if (is_sky[k]) {
12562 cpl_vector_set(points, nsky, k);
12563 nsky++;
12564 }
12565 }
12566 }
12567
12568 }
12569
12570 cpl_vector_delete(values);
12571 cpl_vector_delete(points);
12572
12573 cpl_image_copy(skymap, exslit, 1, ylow+1);
12574 cpl_image_delete(exslit);
12575
12576 }
12577 else {
12578 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
12579 xdata = cpl_image_get_data(exslit);
12580 values = cpl_vector_new(nsky);
12581
12582 for (j = 0; j < nx; j++) {
12583 nsky = 0;
12584 for (k = ylow; k < yhig; k++) {
12585 if (is_sky[k]) {
12586 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
12587 nsky++;
12588 }
12589 }
12590
12591 median = cpl_vector_get_median_const(values);
12592
12593 for (k = ylow; k < yhig; k++)
12594 xdata[j+(k-ylow)*nx] = median;
12595
12596 }
12597
12598 cpl_vector_delete(values);
12599
12600 cpl_image_copy(skymap, exslit, 1, ylow+1);
12601 cpl_image_delete(exslit);
12602 }
12603 }
12604 else
12605 cpl_msg_warning(func, "Too few sky points in slit %d", i + 1);
12606 }
12607
12608 cpl_free(is_sky);
12609
12610 return skymap;
12611
12612 }
12613
12614
12636 cpl_error_code mos_clean_cosmics(cpl_image *image, float gain,
12637 float threshold, float ratio)
12638 {
12639 const char *func = "mos_clean_cosmics";
12640
12641 cpl_image *smoothImage;
12642 cpl_table *table;
12643 cpl_matrix *kernel;
12644 int *xdata;
12645 int *ydata;
12646 float *idata;
12647 float *sdata;
12648 float sigma, sum, value, smoothValue;
12649 double noise;
12650 int count;
12651 float fMax;
12652 int iMin, iMax, jMin, jMax, iPosMax, jPosMax;
12653 int xLen;
12654 int yLen;
12655 int nPix;
12656 int first = 1;
12657
12658 int pos, i, j, k, l, ii, jj, iii = 0, jjj = 0;
12659 int numCosmic = 0;
12660 int found, foundContiguousCandidate;
12661 int *cosmic;
12662
12663
12664 if (image == NULL)
12665 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12666
12667
12668
12669
12670
12671
12672
12673
12674
12675
12676
12677
12678 xLen = cpl_image_get_size_x(image);
12679 yLen = cpl_image_get_size_y(image);
12680
12681 if (xLen < 4 || yLen < 4)
12682 return CPL_ERROR_NONE;
12683
12684 nPix = xLen * yLen;
12685
12686
12687
12688
12689
12690
12691
12692
12693
12694
12695
12696
12697
12698
12699
12700
12701
12702
12703
12704
12705
12706
12707 idata = cpl_image_get_data(image);
12708 noise = 0.0;
12709 count = 0;
12710
12711 for (i = 0; i < nPix; i++) {
12712 if (idata[i] < -0.00001) {
12713 noise -= idata[i];
12714 count++;
12715 }
12716 }
12717
12718 noise /= count;
12719 noise *= 1.25;
12720
12721 cosmic = cpl_calloc(nPix, sizeof(int));
12722
12723 if (threshold < 0.)
12724 threshold = 4.0;
12725 if (ratio < 0.)
12726 ratio = 2.0;
12727
12728 kernel = cpl_matrix_new(3, 3);
12729 cpl_matrix_fill(kernel, 1.0);
12730 cpl_matrix_set(kernel, 1, 1, 0.0);
12731 smoothImage = cpl_image_filter_median(image, kernel);
12732 cpl_matrix_delete(kernel);
12733
12734
12735
12736
12737
12738
12739
12740
12741
12742
12743 sdata = cpl_image_get_data(smoothImage);
12744
12745 for (j = 1; j < yLen - 1; j++) {
12746 for (i = 1; i < xLen - 1; i++) {
12747 value = idata[i + j * xLen];
12748 smoothValue = sdata[i + j * xLen];
12749 if (smoothValue < 1.0)
12750 smoothValue = 1.0;
12751 sigma = sqrt(noise * noise + smoothValue / gain);
12752 if (value - smoothValue >= threshold * sigma)
12753 cosmic[i + j * xLen] = -1;
12754 }
12755 }
12756
12757 cpl_image_delete(smoothImage);
12758
12759
12760
12761
12762
12763
12764 do {
12765 found = 0;
12766 for (pos = first; pos < nPix; pos++) {
12767 if (cosmic[pos] == -1) {
12768 cosmic[pos] = 2;
12769 i = pos % xLen;
12770 j = pos / xLen;
12771 first = pos;
12772 first++;
12773 found = 1;
12774 break;
12775 }
12776 }
12777
12778 if (found) {
12779
12780
12781
12782
12783
12784
12785
12786
12787 iMin = iMax = iPosMax = i;
12788 jMin = jMax = jPosMax = j;
12789 fMax = idata[i + j * xLen];
12790
12791 do {
12792 foundContiguousCandidate = 0;
12793 for (l = 0; l <= 1; l++) {
12794 for (k = 0; k <= 1; k++) {
12795
12796
12797
12798
12799
12800 ii = i + k - l;
12801 jj = j + k + l - 1;
12802 if (cosmic[ii + jj * xLen] == -1) {
12803 foundContiguousCandidate = 1;
12804 cosmic[ii + jj * xLen] = 2;
12805
12806 iii = ii;
12807 jjj = jj;
12808
12809
12810
12811
12812
12813 if (ii < iMin)
12814 iMin = ii;
12815 if (ii > iMax)
12816 iMax = ii;
12817 if (jj < jMin)
12818 jMin = jj;
12819 if (jj > jMax)
12820 jMax = jj;
12821
12822 if (idata[ii + jj * xLen] > fMax) {
12823 fMax = idata[ii + jj * xLen];
12824 iPosMax = ii;
12825 jPosMax = jj;
12826 }
12827 }
12828 }
12829 }
12830
12831
12832
12833
12834
12835
12836 cosmic[i + j * xLen] = 3;
12837
12838 if (foundContiguousCandidate) {
12839
12840
12841
12842
12843
12844
12845 i = iii;
12846 j = jjj;
12847
12848
12849
12850
12851
12852 continue;
12853 }
12854
12855
12856
12857
12858
12859
12860 for (l = jMin; l <= jMax; l++) {
12861 for (k = iMin; k <= iMax; k++) {
12862 if (cosmic[k + l * xLen] == 2) {
12863 i = k;
12864 j = l;
12865 foundContiguousCandidate = 1;
12866 break;
12867 }
12868 }
12869 if (foundContiguousCandidate)
12870 break;
12871 }
12872 } while (foundContiguousCandidate);
12873
12874
12875
12876
12877
12878
12879
12880 sum = 0.;
12881 for (l = -1; l <= 1; l++) {
12882 for (k = -1; k <= 1; k++) {
12883 if (l != 0 || k != 0) {
12884 sum += idata[iPosMax + k + (jPosMax + l) * xLen];
12885 }
12886 }
12887 }
12888
12889 sum /= 8.;
12890 if (fMax > ratio * sum) {
12891 for (l = jMin - 1; l <= jMax + 1; l++) {
12892 for (k = iMin - 1; k <= iMax + 1; k++) {
12893 if (cosmic[k + l * xLen] == 3) {
12894 cosmic[k + l * xLen] = 1;
12895 numCosmic++;
12896 }
12897 }
12898 }
12899 }
12900 else {
12901 for (l = jMin - 1; l <= jMax + 1; l++) {
12902 for (k = iMin - 1; k <= iMax + 1; k++) {
12903 if (cosmic[k + l * xLen] != -1) {
12904 if (cosmic[k + l * xLen] == 1)
12905 numCosmic--;
12906 cosmic[k + l * xLen] = 0;
12907 }
12908 }
12909 }
12910 }
12911 }
12912 } while (found);
12913
12914
12915
12916
12917
12918
12919 table = cpl_table_new(numCosmic);
12920 cpl_table_new_column(table, "x", CPL_TYPE_INT);
12921 cpl_table_new_column(table, "y", CPL_TYPE_INT);
12922 cpl_table_set_column_unit(table, "x", "pixel");
12923 cpl_table_set_column_unit(table, "y", "pixel");
12924 xdata = cpl_table_get_data_int(table, "x");
12925 ydata = cpl_table_get_data_int(table, "y");
12926
12927 for (pos = 0, i = 0; pos < nPix; pos++) {
12928 if (cosmic[pos] == 1) {
12929 xdata[i] = (pos % xLen);
12930 ydata[i] = (pos / xLen);
12931 i++;
12932 }
12933 }
12934
12935 mos_clean_bad_pixels(image, table, 1);
12936
12937 cpl_free(cosmic);
12938 cpl_table_delete(table);
12939
12940 return CPL_ERROR_NONE;
12941
12942 }
12943
12944
12945 cpl_error_code mos_clean_bad_pixels(cpl_image *image, cpl_table *table,
12946 int spectral)
12947 {
12948 const char *func = "mos_clean_cosmics";
12949
12950 float *idata;
12951 int *isBadPix;
12952 int i, j, k, d;
12953 int xlen, ylen, totPix;
12954 int nBadPixels = 0;
12955 int sign, foundFirst;
12956 int *xValue = NULL;
12957 int *yValue = NULL;
12958 float save = 0.;
12959 double sumd;
12960 int cx, cy;
12961 int nPairs;
12962 float estimate[4];
12963 int sx[] = {0, 1, 1, 1};
12964 int sy[] = {1,-1, 0, 1};
12965 int searchHorizon = 100;
12966 int percent = 15;
12967
12968
12969 if (image == NULL || table == NULL)
12970 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12971
12972 if (1 != cpl_table_has_column(table, "x"))
12973 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
12974
12975 if (1 != cpl_table_has_column(table, "y"))
12976 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
12977
12978 if (CPL_TYPE_INT != cpl_table_get_column_type(table, "x"))
12979 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
12980
12981 if (CPL_TYPE_INT != cpl_table_get_column_type(table, "y"))
12982 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
12983
12984 nBadPixels = cpl_table_get_nrow(table);
12985
12986 if (nBadPixels) {
12987 xlen = cpl_image_get_size_x(image);
12988 ylen = cpl_image_get_size_y(image);
12989 idata = cpl_image_get_data(image);
12990 totPix = xlen * ylen;
12991 if (((float) nBadPixels) / ((float) totPix) < percent/100.) {
12992 isBadPix = cpl_calloc(totPix, sizeof(int));
12993 }
12994 else {
12995 cpl_msg_warning(func, "Too many bad pixels (> %d%%): "
12996 "skip bad pixel correction", percent);
12997 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12998 }
12999 }
13000 else {
13001 cpl_msg_debug(func, "No pixel values to interpolate");
13002 return CPL_ERROR_NONE;
13003 }
13004
13005 xValue = cpl_table_get_data_int(table, "x");
13006 yValue = cpl_table_get_data_int(table, "y");
13007
13008 for (i = 0; i < nBadPixels; i++)
13009 isBadPix[xValue[i] + yValue[i] * xlen] = 1;
13010
13011 for (i = 0; i < nBadPixels; i++) {
13012
13013
13014
13015
13016
13017
13018
13019
13020
13021
13022
13023
13024
13025 nPairs = 0;
13026 for (j = 0; j < 4; j++) {
13027
13028 if (spectral)
13029 if (j != 2)
13030 continue;
13031
13032 estimate[nPairs] = 0.;
13033 sumd = 0.;
13034 foundFirst = 0;
13035 for (k = 0; k < 2; k++) {
13036 sign = 2 * k - 1;
13037 d = 0;
13038 cx = xValue[i];
13039 cy = yValue[i];
13040 do {
13041 cx += sign * sx[j];
13042 cy += sign * sy[j];
13043 if (cx < 0 || cx >= xlen || cy < 0 || cy >= ylen)
13044 break;
13045 d++;
13046 } while (isBadPix[cx + cy * xlen] && d < searchHorizon);
13047
13048 if (cx >= 0 && cx < xlen &&
13049 cy >= 0 && cy < ylen && d < searchHorizon) {
13050
13051
13052
13053
13054
13055 save = idata[cx + cy * xlen];
13056 estimate[nPairs] += save / d;
13057 sumd += 1. / (double) d;
13058 if (k) {
13059 estimate[nPairs] /= sumd;
13060 nPairs++;
13061 }
13062 else {
13063 foundFirst = 1;
13064 }
13065 }
13066 else {
13067
13068
13069
13070
13071
13072 if (k) {
13073 if (foundFirst) {
13074 estimate[nPairs] = save;
13075 nPairs++;
13076 }
13077 }
13078 }
13079 }
13080 }
13081
13082
13083
13084
13085
13086
13087
13088 if (nPairs > 2) {
13089 idata[xValue[i] + yValue[i] * xlen] =
13090 cpl_tools_get_median_float(estimate, nPairs);
13091 }
13092 else if (nPairs == 2) {
13093 idata[xValue[i] + yValue[i] * xlen] =
13094 (estimate[0] + estimate[1]) / 2.;
13095 }
13096 else if (nPairs == 1) {
13097 idata[xValue[i] + yValue[i] * xlen] = estimate[0];
13098 }
13099 else {
13100 cpl_msg_debug(func, "Cannot correct bad pixel %d,%d\n",
13101 xValue[i], yValue[i]);
13102 }
13103 }
13104
13105 cpl_free(isBadPix);
13106
13107 return CPL_ERROR_NONE;
13108 }
13109
13110
13140 cpl_image *mos_spatial_map(cpl_image *spectra, cpl_table *slits,
13141 cpl_table *polytraces, double reference,
13142 double blue, double red, double dispersion)
13143 {
13144 const char *func = "mos_spatial_map";
13145
13146 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
13147
13148 cpl_polynomial *polytop;
13149 cpl_polynomial *polybot;
13150 cpl_image *calibration;
13151 float *data;
13152 double top, bot;
13153 double coeff;
13154 double ytop, ybot;
13155 double ypos, yfra;
13156 double factor;
13157 int yint, yprev;
13158 int nslits;
13159 int npseudo;
13160 int *slit_id;
13161 int *length;
13162 int nx, ny;
13163 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
13164 int missing_top, missing_bot;
13165 int null;
13166 int order;
13167 int i, j, k;
13168
13169
13170 if (spectra == NULL || slits == NULL || polytraces == NULL) {
13171 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13172 return NULL;
13173 }
13174
13175 if (dispersion <= 0.0) {
13176 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13177 return NULL;
13178 }
13179
13180 if (red - blue < dispersion) {
13181 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13182 return NULL;
13183 }
13184
13185 nx = cpl_image_get_size_x(spectra);
13186 ny = cpl_image_get_size_y(spectra);
13187
13188 calibration = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
13189 data = cpl_image_get_data(calibration);
13190
13191 length = cpl_table_get_data_int(slits, "length");
13192 nslits = cpl_table_get_nrow(slits);
13193 slit_id = cpl_table_get_data_int(slits, "slit_id");
13194 order = cpl_table_get_ncol(polytraces) - 2;
13195
13196
13197
13198
13199
13200
13201 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
13202 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
13203
13204 for (i = 0; i < nslits; i++) {
13205
13206 if (length[i] == 0)
13207 continue;
13208
13209
13210
13211
13212
13213
13214
13215
13216
13217
13218
13219
13220 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
13221
13222 start_pixel = refpixel - pixel_below;
13223 if (start_pixel < 0)
13224 start_pixel = 0;
13225
13226 end_pixel = refpixel + pixel_above;
13227 if (end_pixel > nx)
13228 end_pixel = nx;
13229
13230
13231
13232
13233
13234
13235 missing_top = 0;
13236 polytop = cpl_polynomial_new(1);
13237 for (k = 0; k <= order; k++) {
13238 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
13239 if (null) {
13240 cpl_polynomial_delete(polytop);
13241 missing_top = 1;
13242 break;
13243 }
13244 cpl_polynomial_set_coeff(polytop, &k, coeff);
13245 }
13246
13247 missing_bot = 0;
13248 polybot = cpl_polynomial_new(1);
13249 for (k = 0; k <= order; k++) {
13250 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
13251 if (null) {
13252 cpl_polynomial_delete(polybot);
13253 missing_bot = 1;
13254 break;
13255 }
13256 cpl_polynomial_set_coeff(polybot, &k, coeff);
13257 }
13258
13259 if (missing_top && missing_bot) {
13260 cpl_msg_warning(func, "Spatial map, slit %d was not traced!",
13261 slit_id[i]);
13262 continue;
13263 }
13264
13265
13266
13267
13268
13269
13270
13271 if (missing_top) {
13272 cpl_msg_warning(func, "Upper edge of slit %d was not traced: "
13273 "the spectral curvature of the lower edge "
13274 "is used instead.", slit_id[i]);
13275 polytop = cpl_polynomial_duplicate(polybot);
13276 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
13277 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
13278 k = 0;
13279 coeff = cpl_polynomial_get_coeff(polybot, &k);
13280 coeff += ytop - ybot;
13281 cpl_polynomial_set_coeff(polytop, &k, coeff);
13282 }
13283
13284 if (missing_bot) {
13285 cpl_msg_warning(func, "Lower edge of slit %d was not traced: "
13286 "the spectral curvature of the upper edge "
13287 "is used instead.", slit_id[i]);
13288 polybot = cpl_polynomial_duplicate(polytop);
13289 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
13290 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
13291 k = 0;
13292 coeff = cpl_polynomial_get_coeff(polytop, &k);
13293 coeff -= ytop - ybot;
13294 cpl_polynomial_set_coeff(polybot, &k, coeff);
13295 }
13296
13297 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
13298 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
13299 npseudo = ceil(top-bot) + 1;
13300
13301 if (npseudo < 1) {
13302 cpl_polynomial_delete(polytop);
13303 cpl_polynomial_delete(polybot);
13304 cpl_msg_warning(func, "Slit %d was badly traced: no extraction!",
13305 slit_id[i]);
13306 continue;
13307 }
13308
13309 for (j = start_pixel; j < end_pixel; j++) {
13310 top = cpl_polynomial_eval_1d(polytop, j, NULL);
13311 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
13312 factor = (top-bot)/npseudo;
13313 for (k = 0; k <= npseudo; k++) {
13314 ypos = top - k*factor;
13315 yint = ypos;
13316 yfra = ypos - yint;
13317 if (yint >= 0 && yint < ny-1) {
13318 data[j + nx*yint] = (top-yint)/factor;
13319 if (k) {
13320
13321
13322
13323
13324
13325
13326
13327 if (yprev - yint > 1) {
13328 data[j + nx*(yint+1)] = (top-yint-1)/factor;
13329 }
13330 }
13331 }
13332 yprev = yint;
13333 }
13334 }
13335 cpl_polynomial_delete(polytop);
13336 cpl_polynomial_delete(polybot);
13337 }
13338
13339 return calibration;
13340 }
13341
13342
13405 cpl_image *mos_detect_objects(cpl_image *image, cpl_table *slits, int margin,
13406 int maxradius, int conradius)
13407 {
13408 const char *func = "mos_detect_objects";
13409
13410 cpl_image *profile;
13411 float *pdata;
13412 float *p;
13413
13414 char name[MAX_COLNAME];
13415
13416 int nslits;
13417 int npeaks;
13418 int nobjects, objpos, totobj;
13419 int maxobjects;
13420 int *position;
13421 int *length;
13422 int *reject;
13423 double *place;
13424 double *bright;
13425 double mindistance;
13426 int pos, count;
13427 int up;
13428 int low, hig;
13429 int row;
13430 int i, j, k;
13431
13432 const int min_pixels = 10;
13433
13434
13435 if (cpl_error_get_code() != CPL_ERROR_NONE)
13436 return NULL;
13437
13438 if (image == NULL || slits == NULL) {
13439 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13440 return NULL;
13441 }
13442
13443 if (margin < 0)
13444 margin = 0;
13445
13446 if (maxradius < 0) {
13447 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13448 return NULL;
13449 }
13450
13451 if (conradius < 0) {
13452 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13453 return NULL;
13454 }
13455
13456 nslits = cpl_table_get_nrow(slits);
13457 position = cpl_table_get_data_int(slits, "position");
13458 length = cpl_table_get_data_int(slits, "length");
13459
13460 profile = cpl_image_collapse_create(image, 1);
13461 cpl_image_divide_scalar(profile, cpl_image_get_size_x(image));
13462 pdata = cpl_image_get_data(profile);
13463
13464 row = 1;
13465 maxobjects = 0;
13466 totobj = 0;
13467 for (i = 0; i < nslits; i++) {
13468
13469 if (length[i] == 0)
13470 continue;
13471
13472 pos = position[i] + margin;
13473 count = length[i] - 2*margin;
13474
13475 if (count < min_pixels)
13476 continue;
13477
13478 p = pdata + pos;
13479
13480
13481
13482
13483
13484
13485 npeaks = 0;
13486 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
13487 npeaks++;
13488 }
13489
13490 up = 0;
13491 for (j = 0; j < count - 3; j++) {
13492 if (p[j] > 0) {
13493 if (p[j+1] > p[j]) {
13494 up++;
13495 }
13496 else {
13497 if (up > 2) {
13498 if (p[j+1] > p[j+2] && p[j+2] > 0) {
13499 if (p[j] > 5)
13500 npeaks++;
13501 }
13502 }
13503 else if (up > 1) {
13504 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
13505 if (p[j] > 5)
13506 npeaks++;
13507 }
13508 }
13509 up = 0;
13510 }
13511 }
13512 else {
13513 up = 0;
13514 }
13515 }
13516
13517 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
13518 && p[count-3] > p[count-4] && p[count-4] > 0) {
13519 npeaks++;
13520 }
13521
13522 if (npeaks == 0)
13523 continue;
13524
13525
13526
13527
13528
13529
13530 reject = cpl_calloc(npeaks, sizeof(int));
13531 bright = cpl_calloc(npeaks, sizeof(double));
13532 place = cpl_calloc(npeaks, sizeof(double));
13533
13534 npeaks = 0;
13535 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
13536 bright[0] = p[0];
13537 place[0] = position[i] + margin;
13538 npeaks++;
13539 }
13540
13541 up = 0;
13542 for (j = 0; j < count - 3; j++) {
13543 if (p[j] > 0) {
13544 if (p[j+1] > p[j]) {
13545 up++;
13546 }
13547 else {
13548 if (up > 2) {
13549 if (p[j+1] > p[j+2] && p[j+2] > 0) {
13550 if (p[j] > 5) {
13551 bright[npeaks] = p[j];
13552 place[npeaks] = position[i] + margin + j + 1
13553 + values_to_dx(p[j-1], p[j], p[j+1]);
13554 npeaks++;
13555 }
13556 }
13557 }
13558 else if (up > 1) {
13559 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
13560 if (p[j] > 5) {
13561 bright[npeaks] = p[j];
13562 place[npeaks] = position[i] + margin + j + 1
13563 + values_to_dx(p[j-1], p[j], p[j+1]);
13564 npeaks++;
13565 }
13566 }
13567 }
13568 up = 0;
13569 }
13570 }
13571 else {
13572 up = 0;
13573 }
13574 }
13575
13576 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
13577 && p[count-3] > p[count-4] && p[count-4] > 0) {
13578 bright[npeaks] = p[count-1];
13579 place[npeaks] = position[i] + count;
13580 npeaks++;
13581 }
13582
13583
13584
13585
13586
13587
13588 if (fabs(place[0] - pos) < 1.0)
13589 reject[0] = 1;
13590 if (fabs(place[npeaks-1] - pos - count) < 1.0)
13591 reject[npeaks-1] = 1;
13592 for (j = 0; j < npeaks; j++) {
13593 for (k = 0; k < npeaks; k++) {
13594 if (k == j)
13595 continue;
13596 mindistance = conradius * bright[k] / bright[j]
13597 * bright[k] / bright[j];
13598 if (fabs(place[j] - place[k]) < mindistance)
13599 reject[j] = 1;
13600 }
13601 }
13602
13603
13604 for (j = 0; j < npeaks; j++) {
13605 if (reject[j])
13606 continue;
13607 if (j) {
13608 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
13609 / (bright[j-1] + bright[j]) + 1;
13610 }
13611 else {
13612 low = pos;
13613 }
13614 if (j < npeaks - 1) {
13615 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
13616 / (bright[j+1] + bright[j]) + 1;
13617 }
13618 else {
13619 hig = pos + count;
13620 }
13621
13622 if (low < pos)
13623 low = pos;
13624 if (hig > pos + count)
13625 hig = pos + count;
13626 if (place[j] - low > maxradius)
13627 low = place[j] - maxradius;
13628 if (hig - place[j] > maxradius)
13629 hig = place[j] + maxradius;
13630 if (hig == low)
13631 reject[j] = 1;
13632 }
13633
13634
13635 nobjects = npeaks;
13636 for (j = 0; j < npeaks; j++)
13637 if (reject[j])
13638 nobjects--;
13639
13640 for (j = 0; j < nobjects; j++) {
13641 snprintf(name, MAX_COLNAME, "object_%d", j+1);
13642 if (cpl_table_has_column(slits, name))
13643 continue;
13644 cpl_table_new_column(slits, name, CPL_TYPE_DOUBLE);
13645 snprintf(name, MAX_COLNAME, "start_%d", j+1);
13646 cpl_table_new_column(slits, name, CPL_TYPE_INT);
13647 cpl_table_set_column_unit(slits, name, "pixel");
13648 snprintf(name, MAX_COLNAME, "end_%d", j+1);
13649 cpl_table_new_column(slits, name, CPL_TYPE_INT);
13650 cpl_table_set_column_unit(slits, name, "pixel");
13651 snprintf(name, MAX_COLNAME, "row_%d", j+1);
13652 cpl_table_new_column(slits, name, CPL_TYPE_INT);
13653 cpl_table_set_column_unit(slits, name, "pixel");
13654 }
13655
13656 objpos = nobjects;
13657 for (j = 0; j < npeaks; j++) {
13658 if (reject[j])
13659 continue;
13660 if (j) {
13661 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
13662 / (bright[j-1] + bright[j]) + 1;
13663 }
13664 else {
13665 low = pos;
13666 }
13667 if (j < npeaks - 1) {
13668 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
13669 / (bright[j+1] + bright[j]) + 1;
13670 }
13671 else {
13672 hig = pos + count;
13673 }
13674
13675 if (low < pos)
13676 low = pos;
13677 if (hig > pos + count)
13678 hig = pos + count;
13679 if (place[j] - low > maxradius)
13680 low = place[j] - maxradius;
13681 if (hig - place[j] > maxradius)
13682 hig = place[j] + maxradius;
13683
13684 snprintf(name, MAX_COLNAME, "object_%d", objpos);
13685 cpl_table_set_double(slits, name, i, place[j]);
13686 snprintf(name, MAX_COLNAME, "start_%d", objpos);
13687 cpl_table_set_int(slits, name, i, low);
13688 snprintf(name, MAX_COLNAME, "end_%d", objpos);
13689 cpl_table_set_int(slits, name, i, hig);
13690 snprintf(name, MAX_COLNAME, "row_%d", objpos);
13691 cpl_table_set_int(slits, name, i, row + objpos - 1);
13692 totobj++;
13693 objpos--;
13694 }
13695
13696 row += nobjects;
13697
13698 if (maxobjects < nobjects)
13699 maxobjects = nobjects;
13700
13701 cpl_free(reject);
13702 cpl_free(bright);
13703 cpl_free(place);
13704
13705 }
13706
13707
13708 row = cpl_table_get_nrow(slits);
13709
13710 for (i = 0; i < row; i++) {
13711 for (j = 0; j < maxobjects; j++) {
13712 snprintf(name, MAX_COLNAME, "row_%d", j+1);
13713 if (cpl_table_is_valid(slits, name, i))
13714 cpl_table_set_int(slits, name, i, totobj -
13715 cpl_table_get_int(slits, name, i, NULL));
13716 }
13717 }
13718
13719 for (i = 0; i < maxobjects; i++) {
13720 snprintf(name, MAX_COLNAME, "start_%d", i+1);
13721 cpl_table_fill_invalid_int(slits, name, -1);
13722 snprintf(name, MAX_COLNAME, "end_%d", i+1);
13723 cpl_table_fill_invalid_int(slits, name, -1);
13724 snprintf(name, MAX_COLNAME, "row_%d", i+1);
13725 cpl_table_fill_invalid_int(slits, name, -1);
13726 }
13727
13728 return profile;
13729 }
13730
13731
13756 cpl_image **mos_extract_objects(cpl_image *science, cpl_image *sky,
13757 cpl_table *objects, int extraction, double ron,
13758 double gain, int ncombined)
13759 {
13760 const char *func = "mos_extract_objects";
13761
13762 char name[MAX_COLNAME];
13763
13764 cpl_image **output;
13765 cpl_image *extracted;
13766 cpl_image *extr_sky;
13767 cpl_image *error;
13768 cpl_image *sciwin;
13769 cpl_image *skywin;
13770 int nslits;
13771 int nobjects;
13772 int maxobjects;
13773 int nx, ny;
13774 int ylow, yhig;
13775 int i, j;
13776
13777
13778 if (science == NULL || sky == NULL) {
13779 cpl_msg_error(func, "Both scientific exposures are required in input");
13780 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13781 return NULL;
13782 }
13783
13784 if (objects == NULL) {
13785 cpl_msg_error(func, "An object table is required in input");
13786 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13787 return NULL;
13788 }
13789
13790 if (extraction < 0 || extraction > 1) {
13791 cpl_msg_error(func, "Invalid extraction mode (%d): it should be "
13792 "either 0 or 1", extraction);
13793 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13794 return NULL;
13795 }
13796
13797 if (ron < 0.0) {
13798 cpl_msg_error(func, "Invalid read-out-noise (%f ADU)", ron);
13799 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13800 return NULL;
13801 }
13802
13803 if (gain < 0.1) {
13804 cpl_msg_error(func, "Invalid gain factor (%f e-/ADU)", gain);
13805 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13806 return NULL;
13807 }
13808
13809 if (ncombined < 1) {
13810 cpl_msg_error(func, "Invalid number of combined frames (%d): "
13811 "it should be at least 1", ncombined);
13812 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13813 return NULL;
13814 }
13815
13816
13817
13818
13819
13820
13821
13822 maxobjects = 1;
13823 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
13824 while (cpl_table_has_column(objects, name)) {
13825 maxobjects++;
13826 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
13827 }
13828
13829
13830
13831
13832
13833
13834 nobjects = 0;
13835 nslits = cpl_table_get_nrow(objects);
13836
13837 for (i = 0; i < nslits; i++) {
13838 for (j = 1; j < maxobjects; j++) {
13839 snprintf(name, MAX_COLNAME, "object_%d", j);
13840 if (cpl_table_is_valid(objects, name, i))
13841 nobjects++;
13842 }
13843 }
13844
13845 if (nobjects == 0)
13846 return NULL;
13847
13848 nx = cpl_image_get_size_x(science);
13849 ny = cpl_image_get_size_x(science);
13850
13851 output = cpl_calloc(3, sizeof(cpl_image *));
13852 extracted = output[0] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
13853 extr_sky = output[1] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
13854 error = output[2] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
13855
13856
13857
13858
13859
13860
13861 nobjects = 0;
13862 for (i = 0; i < nslits; i++) {
13863 for (j = 1; j < maxobjects; j++) {
13864 snprintf(name, MAX_COLNAME, "object_%d", j);
13865 if (cpl_table_is_valid(objects, name, i)) {
13866 snprintf(name, MAX_COLNAME, "start_%d", j);
13867 ylow = cpl_table_get_int(objects, name, i, NULL);
13868 snprintf(name, MAX_COLNAME, "end_%d", j);
13869 yhig = cpl_table_get_int(objects, name, i, NULL);
13870 snprintf(name, MAX_COLNAME, "row_%d", j);
13871 nobjects = cpl_table_get_int(objects, name, i, NULL);
13872 sciwin = cpl_image_extract(science, 1, ylow+1, nx, yhig);
13873 skywin = cpl_image_extract(sky, 1, ylow+1, nx, yhig);
13874
13875
13876
13877
13878
13879
13880
13881
13882 mos_extraction(sciwin, skywin, extracted, extr_sky, error,
13883 nobjects, extraction, ron, gain, ncombined);
13884
13885
13886
13887
13888
13889 {
13890 cpl_image *total = cpl_image_add_create(sciwin, skywin);
13891 float *data = cpl_image_get_data_float(total);
13892 int size = cpl_image_get_size_x(total)
13893 * cpl_image_get_size_y(total);
13894 int k;
13895 char *saturation_level = getenv("SATURATION_LEVEL");
13896 float saturation = 62000.0;
13897 char *max_saturated = getenv("MAX_SATURATED");
13898 int max_satur = 10;
13899 int saturated;
13900
13901 if (saturation_level)
13902 saturation = atof(saturation_level);
13903
13904 if (max_saturated)
13905 max_satur = atoi(max_saturated);
13906
13907 saturated = 0;
13908 for (k = 0; k < size; k++) {
13909 if (data[k] > saturation) {
13910 saturated++;
13911 if (saturated > max_satur) {
13912 break;
13913 }
13914 }
13915 }
13916
13917 if (saturated > max_satur)
13918 saturated = 1;
13919 else
13920 saturated = 0;
13921
13922 data = cpl_image_get_data(extracted);
13923 data[nobjects * nx] = saturated;
13924 }
13925
13926 cpl_image_delete(sciwin);
13927 cpl_image_delete(skywin);
13928 nobjects++;
13929 }
13930 }
13931 }
13932
13933 return output;
13934
13935 }
13936
13937
13960 int mos_spectral_resolution(cpl_image *image, double lambda, double startwave,
13961 double dispersion, int saturation,
13962 double *mfwhm, double *rmsfwhm,
13963 double *resolution, double *rmsres, int *nlines)
13964 {
13965 cpl_vector *vector;
13966
13967 int i, j, n, m;
13968 int position, maxpos;
13969 int xlen, ylen;
13970 int sp, ep;
13971 int radius;
13972 int sradius = 40;
13973 int threshold = 250;
13974
13975 int ifwhm;
13976 double fwhm;
13977 double *buffer;
13978 double min, max, halfmax;
13979 double cut = 1.5;
13980 double value, rms;
13981
13982 float *data;
13983
13984
13985 *resolution = 0.0;
13986 *rmsres = 0.0;
13987 *nlines = 0;
13988
13989 xlen = cpl_image_get_size_x(image);
13990 ylen = cpl_image_get_size_y(image);
13991 data = cpl_image_get_data(image);
13992
13993 buffer = cpl_malloc(ylen * sizeof(double));
13994
13995
13996
13997
13998
13999 position = floor((lambda - startwave) / dispersion + 0.5);
14000
14001 sp = position - sradius;
14002 ep = position + sradius;
14003
14004 if (sp < 0 || ep > xlen) {
14005 cpl_free(buffer);
14006 return 0;
14007 }
14008
14009 for (i = 0, n = 0; i < ylen; i++) {
14010
14011
14012
14013
14014
14015 radius = mos_lines_width(data + i*xlen + position - sradius,
14016 2*sradius + 1);
14017 if (radius < 5)
14018 radius = 5;
14019
14020 sp = position - radius;
14021 ep = position + radius;
14022
14023 if (sp < 0 || ep > xlen) {
14024 cpl_free(buffer);
14025 return 0;
14026 }
14027
14028
14029
14030
14031
14032
14033 maxpos = sp;
14034 min = max = data[sp + i * xlen];
14035 for (j = sp; j < ep; j++) {
14036 if (data[j + i * xlen] > max) {
14037 max = data[j + i * xlen];
14038 maxpos = j;
14039 }
14040 if (data[j + i * xlen] < min) {
14041 min = data[j + i * xlen];
14042 }
14043 }
14044
14045 if (fabs(min) < 0.0000001)
14046 continue;
14047
14048 if (max - min < threshold)
14049 continue;
14050
14051 if (max > saturation)
14052 continue;
14053
14054
14055
14056
14057
14058
14059
14060
14061 halfmax = (max + min)/ 2.0;
14062
14063 fwhm = 0.0;
14064 ifwhm = 0;
14065 for (j = maxpos; j < maxpos + radius; j++) {
14066 if (j < xlen) {
14067 if (data[j + i * xlen] < halfmax) {
14068 fwhm = ifwhm + (data[j - 1 + i * xlen] - halfmax)
14069 / (data[j - 1 + i * xlen] - data[j + i * xlen]);
14070 break;
14071 }
14072 ifwhm++;
14073 }
14074 }
14075
14076 ifwhm = 0;
14077 for (j = maxpos; j > maxpos - radius; j--) {
14078 if (j >= 0) {
14079 if (data[j + i * xlen] < halfmax) {
14080 fwhm += ifwhm + (data[j + 1 + i * xlen] - halfmax)
14081 / (data[j + 1 + i * xlen] - data[j + i * xlen]);
14082 break;
14083 }
14084 ifwhm++;
14085 }
14086 }
14087
14088 if (fwhm > 3.0) {
14089 buffer[n] = fwhm - 2.0;
14090 n++;
14091 }
14092
14093 }
14094
14095 if (n == 0) {
14096 cpl_free(buffer);
14097 return 0;
14098 }
14099
14100 vector = cpl_vector_wrap(n, buffer);
14101 value = cpl_vector_get_median_const(vector);
14102 cpl_vector_unwrap(vector);
14103
14104 rms = 0.0;
14105 for (i = 0, m = 0; i < n; i++) {
14106 if (fabs(buffer[i] - value) < cut) {
14107 rms += fabs(buffer[i] - value);
14108 m++;
14109 }
14110 }
14111
14112 cpl_free(buffer);
14113
14114 if (m < 3)
14115 return 0;
14116
14117 rms /= m;
14118 rms *= 1.25;
14119
14120 value *= dispersion;
14121 rms *= dispersion;
14122
14123 *mfwhm = value;
14124 *rmsfwhm = rms;
14125
14126 *resolution = lambda / value;
14127 *rmsres = *resolution * rms / value;
14128
14129 *nlines = m;
14130
14131 return 1;
14132 }
14133
14134
14156 cpl_table *mos_resolution_table(cpl_image *image, double startwave,
14157 double dispersion, int saturation,
14158 cpl_vector *lines)
14159 {
14160
14161 cpl_table *table;
14162 double *line;
14163 double fwhm;
14164 double rmsfwhm;
14165 double resolution;
14166 double rmsres;
14167 int nref;
14168 int nlines;
14169 int i;
14170
14171
14172 nref = cpl_vector_get_size(lines);
14173 line = cpl_vector_get_data(lines);
14174
14175 table = cpl_table_new(nref);
14176 cpl_table_new_column(table, "wavelength", CPL_TYPE_DOUBLE);
14177 cpl_table_set_column_unit(table, "wavelength", "Angstrom");
14178 cpl_table_new_column(table, "fwhm", CPL_TYPE_DOUBLE);
14179 cpl_table_set_column_unit(table, "fwhm", "Angstrom");
14180 cpl_table_new_column(table, "fwhm_rms", CPL_TYPE_DOUBLE);
14181 cpl_table_set_column_unit(table, "fwhm_rms", "Angstrom");
14182 cpl_table_new_column(table, "resolution", CPL_TYPE_DOUBLE);
14183 cpl_table_new_column(table, "resolution_rms", CPL_TYPE_DOUBLE);
14184 cpl_table_new_column(table, "nlines", CPL_TYPE_INT);
14185
14186 for (i = 0; i < nref; i++) {
14187 if (mos_spectral_resolution(image, line[i], startwave, dispersion,
14188 saturation, &fwhm, &rmsfwhm,
14189 &resolution, &rmsres, &nlines)) {
14190 cpl_table_set_double(table, "wavelength", i, line[i]);
14191 cpl_table_set_double(table, "fwhm", i, fwhm);
14192 cpl_table_set_double(table, "fwhm_rms", i, rmsfwhm);
14193 cpl_table_set_double(table, "resolution", i, resolution);
14194 cpl_table_set_double(table, "resolution_rms", i, rmsres);
14195 cpl_table_set_int(table, "nlines", i, nlines);
14196 }
14197 else
14198 cpl_table_set_int(table, "nlines", i, 0);
14199 }
14200
14201 if (cpl_table_has_valid(table, "wavelength"))
14202 return table;
14203
14204 cpl_table_delete(table);
14205
14206 return NULL;
14207
14208 }
14209
14210
14228 double mos_integrate_signal(cpl_image *image, cpl_image *wavemap,
14229 int ystart, int yend, double wstart, double wend)
14230 {
14231 const char *func = "mos_integrate_signal";
14232
14233 double sum;
14234 float *sdata;
14235 float *wdata;
14236 int nx, ny;
14237 int x, y;
14238
14239
14240 if (image == NULL || wavemap == NULL) {
14241 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14242 return 0.0;
14243 }
14244
14245 if (ystart > yend || wstart >= wend) {
14246 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14247 return 0.0;
14248 }
14249
14250 nx = cpl_image_get_size_x(image);
14251 ny = cpl_image_get_size_y(image);
14252
14253 if (!(nx == cpl_image_get_size_x(wavemap)
14254 && ny == cpl_image_get_size_y(wavemap))) {
14255 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
14256 return 0.0;
14257 }
14258
14259 if (ystart < 0 || yend > ny) {
14260 cpl_error_set(func, CPL_ERROR_ACCESS_OUT_OF_RANGE);
14261 return 0.0;
14262 }
14263
14264 sdata = cpl_image_get_data(image);
14265 wdata = cpl_image_get_data(wavemap);
14266
14267 sdata += ystart*nx;
14268 wdata += ystart*nx;
14269
14270 sum = 0.0;
14271 for (y = ystart; y < yend; y++) {
14272 for (x = 0; x < nx; x++) {
14273 if (wdata[x] < wstart || wdata[x] > wend)
14274 continue;
14275 sum += sdata[x];
14276 }
14277 sdata += nx;
14278 wdata += nx;
14279 }
14280
14281 return sum;
14282
14283 }
14284
14285
14286
14287
14288
14289
14290
14291
14292
14293
14316 cpl_table *mos_load_slits_fors_mxu(cpl_propertylist *header)
14317 {
14318 const char *func = "mos_load_slits_fors_mxu";
14319
14320 cpl_table *slits;
14321 char keyname[MAX_COLNAME];
14322 const char *instrume;
14323 const char *target_name;
14324 float slit_x;
14325 float slit_y;
14326 float length;
14327
14328 double arc2mm = 0.528;
14329 int nslits;
14330 int slit_id;
14331 int fors;
14332 int chip;
14333 int found;
14334
14335
14336
14337
14338
14339
14340
14341 float low_limit1 = 10.0;
14342 float hig_limit2 = 30.0;
14343
14344
14345 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14346 return NULL;
14347 }
14348
14349 if (header == NULL) {
14350 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14351 return NULL;
14352 }
14353
14354
14355
14356
14357
14358
14359 instrume = cpl_propertylist_get_string(header, "INSTRUME");
14360
14361 fors = 0;
14362 if (instrume[4] == '1')
14363 fors = 1;
14364 if (instrume[4] == '2')
14365 fors = 2;
14366
14367 if (fors != 2) {
14368 cpl_msg_error(func, "Wrong instrument: %s\n"
14369 "FORS2 is expected for MXU data", instrume);
14370 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14371 return NULL;
14372 }
14373
14374
14375
14376
14377
14378
14379
14380
14381 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
14382
14383 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14384 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
14385 "in FITS header");
14386 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14387 return NULL;
14388 }
14389
14390 if (chip != 1 && chip != 2) {
14391 cpl_msg_error(func, "Unexpected chip position in keyword "
14392 "ESO DET CHIP1 Y: %d", chip);
14393 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14394 return NULL;
14395 }
14396
14397
14398
14399
14400
14401
14402
14403 nslits = 0;
14404 slit_id = 0;
14405 found = 1;
14406
14407 while (found) {
14408 slit_id++;
14409 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d YPOS", slit_id + 100);
14410 if (cpl_propertylist_has(header, keyname)) {
14411 slit_y = cpl_propertylist_get_double(header, keyname);
14412
14413 if (chip == 1)
14414 if (slit_y < low_limit1)
14415 continue;
14416 if (chip == 2)
14417 if (slit_y > hig_limit2)
14418 continue;
14419
14420 snprintf(keyname, MAX_COLNAME, "ESO INS TARG%d NAME",
14421 slit_id + 100);
14422 if (cpl_propertylist_has(header, keyname)) {
14423 target_name = cpl_propertylist_get_string(header, keyname);
14424 if (strncmp(target_name, "refslit", 7))
14425 nslits++;
14426 }
14427 else
14428 nslits++;
14429 }
14430 else
14431 found = 0;
14432 }
14433
14434 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14435 cpl_msg_error(func, "%s while loading slits coordinates from "
14436 "FITS header", cpl_error_get_message());
14437 cpl_error_set_where(func);
14438 return NULL;
14439 }
14440
14441 if (nslits == 0) {
14442 cpl_msg_error(func, "No slits coordinates found in header");
14443 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14444 return NULL;
14445 }
14446
14447 slits = cpl_table_new(nslits);
14448 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
14449 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
14450 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
14451 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
14452 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
14453 cpl_table_set_column_unit(slits, "xtop", "pixel");
14454 cpl_table_set_column_unit(slits, "ytop", "pixel");
14455 cpl_table_set_column_unit(slits, "xbottom", "pixel");
14456 cpl_table_set_column_unit(slits, "ybottom", "pixel");
14457
14458 nslits = 0;
14459 slit_id = 0;
14460 found = 1;
14461 while (found) {
14462 slit_id++;
14463 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d YPOS", slit_id + 100);
14464 if (cpl_propertylist_has(header, keyname)) {
14465 slit_y = cpl_propertylist_get_double(header, keyname);
14466
14467 if (chip == 1)
14468 if (slit_y < low_limit1)
14469 continue;
14470 if (chip == 2)
14471 if (slit_y > hig_limit2)
14472 continue;
14473
14474
14475
14476
14477
14478
14479 slit_y = -slit_y;
14480
14481 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d XPOS", slit_id + 100);
14482 slit_x = cpl_propertylist_get_double(header, keyname);
14483 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14484 cpl_table_delete(slits);
14485 cpl_msg_error(func, "Missing keyword %s in FITS header",
14486 keyname);
14487 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14488 return NULL;
14489 }
14490
14491 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d LEN", slit_id + 100);
14492 length = cpl_propertylist_get_double(header, keyname);
14493 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14494 cpl_table_delete(slits);
14495 cpl_msg_error(func, "Missing keyword %s in FITS header",
14496 keyname);
14497 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14498 return NULL;
14499 }
14500
14501 length *= arc2mm;
14502
14503 snprintf(keyname, MAX_COLNAME, "ESO INS TARG%d NAME",
14504 slit_id + 100);
14505 if (cpl_propertylist_has(header, keyname)) {
14506 target_name = cpl_propertylist_get_string(header, keyname);
14507 if (strncmp(target_name, "refslit", 7)) {
14508 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
14509 cpl_table_set(slits, "xtop", nslits, slit_x);
14510 cpl_table_set(slits, "ytop", nslits, slit_y + length/2);
14511 cpl_table_set(slits, "xbottom", nslits, slit_x);
14512 cpl_table_set(slits, "ybottom", nslits, slit_y - length/2);
14513 nslits++;
14514 }
14515 }
14516 else {
14517 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
14518 cpl_table_set(slits, "xtop", nslits, slit_x);
14519 cpl_table_set(slits, "ytop", nslits, slit_y + length/2);
14520 cpl_table_set(slits, "xbottom", nslits, slit_x);
14521 cpl_table_set(slits, "ybottom", nslits, slit_y - length/2);
14522 nslits++;
14523 }
14524 }
14525 else
14526 found = 0;
14527 }
14528
14529 return slits;
14530 }
14531
14532
14555 cpl_table *mos_load_slits_fors_mos(cpl_propertylist *header)
14556 {
14557 const char *func = "mos_load_slits_fors_mos";
14558
14559 cpl_table *slits;
14560 char keyname[MAX_COLNAME];
14561 const char *instrume;
14562 const char *chipname;
14563 float slit_x;
14564 int first_slit, last_slit;
14565 int nslits;
14566 int slit_id;
14567 int fors;
14568 int chip;
14569 int fors_is_old;
14570
14571
14572
14573
14574
14575 float ytop[19] = { 113.9, 101.3, 89.9, 77.3, 65.9, 53.3,
14576 41.9, 29.3, 17.9, 5.3, -6.1, -18.7,
14577 -30.1, -42.7, -54.1, -66.7, -78.1, -90.7,
14578 -102.1 };
14579 float ybottom[19] = { 102.1, 90.7, 78.1, 66.7, 54.1, 42.7,
14580 30.1, 18.7, 6.1, -5.3, -17.9, -29.3,
14581 -41.9, -53.3, -65.9, -77.3, -89.9, -101.3,
14582 -113.9 };
14583
14584
14585 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14586 return NULL;
14587 }
14588
14589 if (header == NULL) {
14590 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14591 return NULL;
14592 }
14593
14594
14595
14596
14597
14598
14599 instrume = cpl_propertylist_get_string(header, "INSTRUME");
14600
14601 fors = 0;
14602 if (instrume[4] == '1')
14603 fors = 1;
14604 if (instrume[4] == '2')
14605 fors = 2;
14606
14607 if (fors == 0) {
14608 cpl_msg_error(func, "Wrong instrument found in FITS header: %s",
14609 instrume);
14610 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14611 return NULL;
14612 }
14613
14614
14615
14616
14617
14618
14619
14620 chipname = cpl_propertylist_get_string(header, "ESO DET CHIP1 ID");
14621
14622 if (chipname[0] == 'M' || chipname[0] == 'N')
14623 fors_is_old = 0;
14624 else
14625 fors_is_old = 1;
14626
14627 if (fors == 1 && fors_is_old) {
14628 first_slit = 1;
14629 last_slit = 19;
14630 }
14631 else {
14632
14633
14634
14635
14636
14637
14638
14639 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
14640
14641 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14642 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
14643 "in FITS header");
14644 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14645 return NULL;
14646 }
14647
14648 if (chip != 1 && chip != 2) {
14649 cpl_msg_error(func, "Unexpected chip position in keyword "
14650 "ESO DET CHIP1 Y: %d", chip);
14651 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14652 return NULL;
14653 }
14654
14655 if (chip == 1) {
14656 first_slit = 12;
14657 last_slit = 19;
14658 }
14659 else {
14660 first_slit = 1;
14661 last_slit = 11;
14662 }
14663 }
14664
14665
14666
14667
14668
14669
14670
14671
14672 nslits = 0;
14673 slit_id = 0;
14674 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
14675 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d POS", slit_id);
14676 if (cpl_propertylist_has(header, keyname)) {
14677 slit_x = cpl_propertylist_get_double(header, keyname);
14678 if (fabs(slit_x) < 115.0)
14679 nslits++;
14680 }
14681 else {
14682 cpl_msg_error(func, "Missing keyword %s in FITS header", keyname);
14683 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14684 return NULL;
14685 }
14686 }
14687
14688 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14689 cpl_msg_error(func, "%s while loading slits coordinates from "
14690 "FITS header", cpl_error_get_message());
14691 cpl_error_set_where(func);
14692 return NULL;
14693 }
14694
14695 if (nslits == 0) {
14696 cpl_msg_error(func, "No slits coordinates found in header");
14697 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14698 return NULL;
14699 }
14700
14701 slits = cpl_table_new(nslits);
14702 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
14703 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
14704 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
14705 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
14706 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
14707 cpl_table_set_column_unit(slits, "xtop", "pixel");
14708 cpl_table_set_column_unit(slits, "ytop", "pixel");
14709 cpl_table_set_column_unit(slits, "xbottom", "pixel");
14710 cpl_table_set_column_unit(slits, "ybottom", "pixel");
14711
14712 nslits = 0;
14713 slit_id = 0;
14714 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
14715 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d POS", slit_id);
14716 slit_x = cpl_propertylist_get_double(header, keyname);
14717 if (fabs(slit_x) < 115.0) {
14718 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
14719 cpl_table_set(slits, "xtop", nslits, slit_x);
14720 cpl_table_set(slits, "ytop", nslits, ytop[slit_id-1]);
14721 cpl_table_set(slits, "xbottom", nslits, slit_x);
14722 cpl_table_set(slits, "ybottom", nslits, ybottom[slit_id-1]);
14723 nslits++;
14724 }
14725 }
14726
14727 return slits;
14728 }
14729
14730
14754 cpl_table *mos_load_slits_fors_lss(cpl_propertylist *header)
14755 {
14756 const char *func = "mos_load_slits_fors_lss";
14757
14758 cpl_table *slits;
14759 char *slit_name;
14760 const char *instrume;
14761 int fors;
14762 int chip;
14763 float ytop;
14764 float ybottom;
14765
14766 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14767 return NULL;
14768 }
14769
14770 if (header == NULL) {
14771 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14772 return NULL;
14773 }
14774
14775
14776
14777
14778
14779
14780 instrume = cpl_propertylist_get_string(header, "INSTRUME");
14781
14782 fors = 0;
14783 if (instrume[4] == '1')
14784 fors = 1;
14785 if (instrume[4] == '2')
14786 fors = 2;
14787
14788 if (fors == 0) {
14789 cpl_msg_error(func, "Wrong instrument found in FITS header: %s",
14790 instrume);
14791 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14792 return NULL;
14793 }
14794
14795 if (fors == 1) {
14796 ytop = 109.94;
14797 ybottom = -109.94;
14798 }
14799 else {
14800
14801
14802
14803
14804
14805
14806
14807 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
14808
14809 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14810 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
14811 "in FITS header");
14812 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14813 return NULL;
14814 }
14815
14816 if (chip != 1 && chip != 2) {
14817 cpl_msg_error(func, "Unexpected chip position in keyword "
14818 "ESO DET CHIP1 Y: %d", chip);
14819 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14820 return NULL;
14821 }
14822
14823 if (chip == 1) {
14824 ytop = 30.0;
14825 ybottom = -109.94;
14826 }
14827 else {
14828 ytop = 109.94;
14829 ybottom = -20.0;
14830 }
14831 }
14832
14833
14834 slits = cpl_table_new(1);
14835 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
14836 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
14837 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
14838 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
14839 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
14840 cpl_table_set_column_unit(slits, "xtop", "pixel");
14841 cpl_table_set_column_unit(slits, "ytop", "pixel");
14842 cpl_table_set_column_unit(slits, "xbottom", "pixel");
14843 cpl_table_set_column_unit(slits, "ybottom", "pixel");
14844
14845 slit_name = (char *)cpl_propertylist_get_string(header,
14846 "ESO INS SLIT NAME");
14847
14848 cpl_table_set(slits, "ytop", 0, ytop);
14849 cpl_table_set(slits, "ybottom", 0, ybottom);
14850
14851 if (!strncmp(slit_name, "lSlit0_3arcsec", 14)) {
14852 cpl_table_set_int(slits, "slit_id", 0, 1);
14853 cpl_table_set(slits, "xbottom", 0, -0.075);
14854 cpl_table_set(slits, "xtop", 0, 0.075);
14855 }
14856 else if (!strncmp(slit_name, "lSlit0_4arcsec", 14)) {
14857 cpl_table_set_int(slits, "slit_id", 0, 2);
14858 cpl_table_set(slits, "xbottom", 0, 5.895);
14859 cpl_table_set(slits, "xtop", 0, 6.105);
14860 }
14861 else if (!strncmp(slit_name, "lSlit0_5arcsec", 14)) {
14862 cpl_table_set_int(slits, "slit_id", 0, 3);
14863 cpl_table_set(slits, "xbottom", 0, -6.135);
14864 cpl_table_set(slits, "xtop", 0, -5.865);
14865 }
14866 else if (!strncmp(slit_name, "lSlit0_7arcsec", 14)) {
14867 cpl_table_set_int(slits, "slit_id", 0, 4);
14868 cpl_table_set(slits, "xbottom", 0, 11.815);
14869 cpl_table_set(slits, "xtop", 0, 12.185);
14870 }
14871 else if (!strncmp(slit_name, "lSlit1_0arcsec", 14)) {
14872 cpl_table_set_int(slits, "slit_id", 0, 5);
14873 cpl_table_set(slits, "xbottom", 0, -12.265);
14874 cpl_table_set(slits, "xtop", 0, -11.735);
14875 }
14876 else if (!strncmp(slit_name, "lSlit1_3arcsec", 14)) {
14877 cpl_table_set_int(slits, "slit_id", 0, 6);
14878 cpl_table_set(slits, "xbottom", 0, 17.655);
14879 cpl_table_set(slits, "xtop", 0, 18.345);
14880 }
14881 else if (!strncmp(slit_name, "lSlit1_6arcsec", 14)) {
14882 cpl_table_set_int(slits, "slit_id", 0, 7);
14883 cpl_table_set(slits, "xbottom", 0, -18.425);
14884 cpl_table_set(slits, "xtop", 0, -17.575);
14885 }
14886 else if (!strncmp(slit_name, "lSlit2_0arcsec", 14)) {
14887 cpl_table_set_int(slits, "slit_id", 0, 8);
14888 cpl_table_set(slits, "xbottom", 0, 23.475);
14889 cpl_table_set(slits, "xtop", 0, 24.525);
14890 }
14891 else if (!strncmp(slit_name, "lSlit2_5arcsec", 14)) {
14892 cpl_table_set_int(slits, "slit_id", 0, 9);
14893 cpl_table_set(slits, "xbottom", 0, -24.66);
14894 cpl_table_set(slits, "xtop", 0, -23.34);
14895 }
14896 else {
14897 cpl_msg_error(func, "Invalid slit %s in keyword ESO INS SLIT NAME",
14898 slit_name);
14899 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
14900 cpl_table_delete(slits);
14901 return NULL;
14902 }
14903
14904 return slits;
14905 }
14906
14907
14922 double mos_get_gain_vimos(cpl_propertylist *header)
14923 {
14924 const char *func = "mos_get_gain_vimos";
14925
14926 double gain = -1.0;
14927
14928
14929 if (cpl_error_get_code() != CPL_ERROR_NONE)
14930 return gain;
14931
14932 if (header == NULL) {
14933 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14934 return gain;
14935 }
14936
14937 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
14938 if (cpl_error_get_code()) {
14939 cpl_error_set_where(func);
14940 gain = -1.0;
14941 }
14942
14943 return gain;
14944
14945 }
14946
14947
14967 cpl_table *mos_load_slits_vimos(cpl_propertylist *header)
14968 {
14969 const char *func = "mos_load_slits_vimos";
14970
14971 cpl_table *slits;
14972 char keyname[MAX_COLNAME];
14973 float slit_x;
14974 float slit_y;
14975 float dim_x;
14976 float dim_y;
14977 int nslits;
14978 int slit_id;
14979 int curved;
14980 int i;
14981
14982
14983 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14984 return NULL;
14985 }
14986
14987 if (header == NULL) {
14988 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14989 return NULL;
14990 }
14991
14992 nslits = cpl_propertylist_get_int(header, "ESO INS SLIT NO");
14993
14994 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14995 cpl_error_set_where(func);
14996 return NULL;
14997 }
14998
14999 slits = cpl_table_new(nslits);
15000 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
15001 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
15002 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
15003 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
15004 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
15005 cpl_table_new_column(slits, "xwidth", CPL_TYPE_DOUBLE);
15006 cpl_table_new_column(slits, "ywidth", CPL_TYPE_DOUBLE);
15007 cpl_table_new_column(slits, "curved", CPL_TYPE_INT);
15008 cpl_table_set_column_unit(slits, "xtop", "pixel");
15009 cpl_table_set_column_unit(slits, "ytop", "pixel");
15010 cpl_table_set_column_unit(slits, "xbottom", "pixel");
15011 cpl_table_set_column_unit(slits, "ybottom", "pixel");
15012 cpl_table_set_column_unit(slits, "xwidth", "mm");
15013 cpl_table_set_column_unit(slits, "ywidth", "mm");
15014
15015 for (i = 0; i < nslits; i++) {
15016 sprintf(keyname, "ESO INS SLIT%d ID", i+1);
15017 slit_id = cpl_propertylist_get_int(header, keyname);
15018 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15019 cpl_error_set_where(func);
15020 return NULL;
15021 }
15022 sprintf(keyname, "ESO INS SLIT%d X", i+1);
15023 slit_x = cpl_propertylist_get_double(header, keyname);
15024 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15025 cpl_error_set_where(func);
15026 return NULL;
15027 }
15028 sprintf(keyname, "ESO INS SLIT%d Y", i+1);
15029 slit_y = cpl_propertylist_get_double(header, keyname);
15030 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15031 cpl_error_set_where(func);
15032 return NULL;
15033 }
15034 sprintf(keyname, "ESO INS SLIT%d DIMX", i+1);
15035 dim_x = cpl_propertylist_get_double(header, keyname);
15036 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15037 cpl_error_set_where(func);
15038 return NULL;
15039 }
15040
15041 sprintf(keyname, "ESO INS SLIT%d BEZIER DY", i+1);
15042 if (cpl_propertylist_has(header, keyname)) {
15043 curved = 1;
15044 }
15045 else {
15046 sprintf(keyname, "ESO INS SLIT%d DIMY", i+1);
15047 curved = 0;
15048 }
15049 dim_y = cpl_propertylist_get_double(header, keyname);
15050 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15051 cpl_error_set_where(func);
15052 return NULL;
15053 }
15054
15055 cpl_table_set_int(slits, "slit_id", i, slit_id);
15056 cpl_table_set(slits, "xtop", i, slit_x - dim_x/2);
15057 cpl_table_set(slits, "ytop", i, slit_y);
15058 cpl_table_set(slits, "xbottom", i, slit_x + dim_x/2);
15059 cpl_table_set(slits, "ybottom", i, slit_y);
15060 cpl_table_set(slits, "xwidth", i, dim_x);
15061 cpl_table_set(slits, "ywidth", i, dim_y);
15062 cpl_table_set_int(slits, "curved", i, curved);
15063 }
15064
15065 return slits;
15066 }
15067
15068
15078 int mos_check_multiplex(cpl_table *slits)
15079 {
15080 cpl_propertylist *sort;
15081 int nrow;
15082 int i, multiplex, xprev, xcur;
15083 double prev, cur;
15084 double tolerance = 1.0;
15085
15086
15087
15088
15089
15090
15091
15092
15093
15094 sort = cpl_propertylist_new();
15095 cpl_propertylist_append_bool(sort, "xtop", 0);
15096 cpl_table_sort(slits, sort);
15097 cpl_propertylist_delete(sort);
15098
15099 prev = cpl_table_get_double(slits, "xtop", 0, NULL);
15100 cpl_table_new_column(slits, "xind", CPL_TYPE_INT);
15101 cpl_table_set_int(slits, "xind", 0, prev);
15102 nrow = cpl_table_get_nrow(slits);
15103 for (i = 1; i < nrow; i++) {
15104 cur = cpl_table_get_double(slits, "xtop", i, NULL);
15105 if (fabs(prev - cur) > tolerance)
15106 prev = cur;
15107 cpl_table_set_int(slits, "xind", i, prev);
15108 }
15109
15110
15111
15112
15113
15114
15115 sort = cpl_propertylist_new();
15116 cpl_propertylist_append_bool(sort, "xind", 0);
15117 cpl_propertylist_append_bool(sort, "ytop", 0);
15118 cpl_table_sort(slits, sort);
15119 cpl_propertylist_delete(sort);
15120
15121
15122
15123
15124
15125 multiplex = 0;
15126 cpl_table_new_column(slits, "multiplex", CPL_TYPE_INT);
15127 xprev = cpl_table_get_int(slits, "xind", 0, NULL);
15128 cpl_table_set_int(slits, "multiplex", 0, multiplex);
15129 nrow = cpl_table_get_nrow(slits);
15130 for (i = 1; i < nrow; i++) {
15131 xcur = cpl_table_get_int(slits, "xind", i, NULL);
15132 if (xcur == xprev) {
15133 multiplex++;
15134 }
15135 else {
15136 xprev = xcur;
15137 multiplex = 0;
15138 }
15139 cpl_table_set_int(slits, "multiplex", i, multiplex);
15140 }
15141
15142 cpl_table_save(slits, NULL, NULL, "multiplex.fits", CPL_IO_DEFAULT);
15143
15144 cpl_table_erase_column(slits, "xind");
15145
15146 return 1 + cpl_table_get_column_max(slits, "multiplex");
15147
15148 }
15149
15150
15177 cpl_table *mos_load_overscans_vimos(const cpl_propertylist *header,
15178 int check_consistency)
15179 {
15180 const char *func = "mos_load_overscans_vimos";
15181
15182 int nx = 0;
15183 int ny = 0;
15184 int px = 0;
15185 int py = 0;
15186 int ox = 0;
15187 int oy = 0;
15188 int vx = 0;
15189 int vy = 0;
15190 int nrows;
15191 cpl_table *overscans;
15192
15193
15194 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15195 cpl_msg_error(func, "Reset your error: %s", cpl_error_get_message());
15196 return NULL;
15197 }
15198
15199 if (header == NULL) {
15200 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15201 return NULL;
15202 }
15203
15204 if (cpl_propertylist_has(header, "NAXIS1"))
15205 nx = cpl_propertylist_get_int(header, "NAXIS1");
15206 if (cpl_propertylist_has(header, "NAXIS2"))
15207 ny = cpl_propertylist_get_int(header, "NAXIS2");
15208 if (cpl_propertylist_has(header, "ESO DET OUT1 PRSCX"))
15209 px = cpl_propertylist_get_int(header, "ESO DET OUT1 PRSCX");
15210 if (cpl_propertylist_has(header, "ESO DET OUT1 PRSCY"))
15211 py = cpl_propertylist_get_int(header, "ESO DET OUT1 PRSCY");
15212 if (cpl_propertylist_has(header, "ESO DET OUT1 OVSCX"))
15213 ox = cpl_propertylist_get_int(header, "ESO DET OUT1 OVSCX");
15214 if (cpl_propertylist_has(header, "ESO DET OUT1 OVSCY"))
15215 oy = cpl_propertylist_get_int(header, "ESO DET OUT1 OVSCY");
15216 if (cpl_propertylist_has(header, "ESO DET OUT1 NX"))
15217 vx = cpl_propertylist_get_int(header, "ESO DET OUT1 NX");
15218 if (cpl_propertylist_has(header, "ESO DET OUT1 NY"))
15219 vy = cpl_propertylist_get_int(header, "ESO DET OUT1 NY");
15220
15221 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15222 cpl_msg_error(func, "Missing overscan keywords in header");
15223 cpl_error_set_where(func);
15224 return NULL;
15225 }
15226
15227 if (px < 0 || py < 0 || ox < 0 || oy < 0) {
15228 cpl_msg_error(func, "Missing overscan keywords in header");
15229 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15230 return NULL;
15231 }
15232
15233 if ((px + vx + ox != nx) || (py + vy + oy != ny)) {
15234 if (check_consistency) {
15235 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15236 return NULL;
15237 }
15238 else {
15239 cpl_msg_debug(func, "Overscans description conflicts with "
15240 "reported image sizes, "
15241 "%d + %d + %d != %d or "
15242 "%d + %d + %d != %d",
15243 px, vx, ox, nx,
15244 py, vy, oy, ny);
15245 }
15246 }
15247
15248 nrows = 0;
15249 if (px > 0)
15250 nrows++;
15251 if (ox > 0)
15252 nrows++;
15253 if (py > 0)
15254 nrows++;
15255 if (oy > 0)
15256 nrows++;
15257
15258 if (nrows > 2) {
15259 cpl_msg_error(func, "Unexpected overscan regions "
15260 "(both in X and Y direction)");
15261 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15262 return NULL;
15263 }
15264
15265
15266
15267
15268
15269
15270
15271 nrows++;
15272
15273 overscans = cpl_table_new(nrows);
15274 cpl_table_new_column(overscans, "xlow", CPL_TYPE_INT);
15275 cpl_table_new_column(overscans, "ylow", CPL_TYPE_INT);
15276 cpl_table_new_column(overscans, "xhig", CPL_TYPE_INT);
15277 cpl_table_new_column(overscans, "yhig", CPL_TYPE_INT);
15278
15279 nrows = 0;
15280
15281 cpl_table_set_int(overscans, "xlow", nrows, px);
15282 cpl_table_set_int(overscans, "ylow", nrows, py);
15283 cpl_table_set_int(overscans, "xhig", nrows, nx - ox);
15284 cpl_table_set_int(overscans, "yhig", nrows, ny - oy);
15285 nrows++;
15286
15287 if (px > 0) {
15288 cpl_table_set_int(overscans, "xlow", nrows, 0);
15289 cpl_table_set_int(overscans, "ylow", nrows, 0);
15290 cpl_table_set_int(overscans, "xhig", nrows, px);
15291 cpl_table_set_int(overscans, "yhig", nrows, ny);
15292 nrows++;
15293 }
15294
15295 if (ox > 0) {
15296 cpl_table_set_int(overscans, "xlow", nrows, nx - ox);
15297 cpl_table_set_int(overscans, "ylow", nrows, 0);
15298 cpl_table_set_int(overscans, "xhig", nrows, nx);
15299 cpl_table_set_int(overscans, "yhig", nrows, ny);
15300 nrows++;
15301 }
15302
15303 if (py > 0) {
15304 cpl_table_set_int(overscans, "xlow", nrows, 0);
15305 cpl_table_set_int(overscans, "ylow", nrows, 0);
15306 cpl_table_set_int(overscans, "xhig", nrows, nx);
15307 cpl_table_set_int(overscans, "yhig", nrows, py);
15308 nrows++;
15309 }
15310
15311 if (oy > 0) {
15312 cpl_table_set_int(overscans, "xlow", nrows, 0);
15313 cpl_table_set_int(overscans, "ylow", nrows, ny - oy);
15314 cpl_table_set_int(overscans, "xhig", nrows, nx);
15315 cpl_table_set_int(overscans, "yhig", nrows, ny);
15316 nrows++;
15317 }
15318
15319 return overscans;
15320
15321 }
15322
15323
15324 cpl_table *mos_load_overscans_fors(const cpl_propertylist *header)
15325 {
15326 const char *func = "mos_load_overscans_fors";
15327
15328 int nports;
15329 int nx = 0;
15330 int ny = 0;
15331 int px = 0;
15332 int py = 0;
15333 int ox = 0;
15334 int oy = 0;
15335 int rebin;
15336 int nrows;
15337 cpl_table *overscans;
15338
15339
15340 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15341 cpl_msg_error(func, "Reset your error: %s", cpl_error_get_message());
15342 return NULL;
15343 }
15344
15345 if (header == NULL) {
15346 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15347 return NULL;
15348 }
15349
15350 if (cpl_propertylist_has(header, "ESO DET OUTPUTS"))
15351 nports = cpl_propertylist_get_int(header, "ESO DET OUTPUTS");
15352
15353 if (nports == 4 &&
15354 cpl_propertylist_has(header, "ESO DET OUT1 PRSCX") &&
15355 cpl_propertylist_has(header, "ESO DET WIN1 BINX")) {
15356
15357 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
15358
15359 overscans = cpl_table_new(3);
15360 cpl_table_new_column(overscans, "xlow", CPL_TYPE_INT);
15361 cpl_table_new_column(overscans, "ylow", CPL_TYPE_INT);
15362 cpl_table_new_column(overscans, "xhig", CPL_TYPE_INT);
15363 cpl_table_new_column(overscans, "yhig", CPL_TYPE_INT);
15364
15365 px = 16 / rebin;
15366 ox = 16 / rebin;
15367 nx = 2080 / rebin;
15368 ny = 2048 / rebin;
15369 nrows = 0;
15370
15371 cpl_table_set_int(overscans, "xlow", nrows, px);
15372 cpl_table_set_int(overscans, "ylow", nrows, py);
15373 cpl_table_set_int(overscans, "xhig", nrows, nx - ox);
15374 cpl_table_set_int(overscans, "yhig", nrows, ny - oy);
15375 nrows++;
15376
15377 cpl_table_set_int(overscans, "xlow", nrows, 0);
15378 cpl_table_set_int(overscans, "ylow", nrows, 0);
15379 cpl_table_set_int(overscans, "xhig", nrows, px);
15380 cpl_table_set_int(overscans, "yhig", nrows, ny);
15381 nrows++;
15382
15383 cpl_table_set_int(overscans, "xlow", nrows, nx - ox);
15384 cpl_table_set_int(overscans, "ylow", nrows, 0);
15385 cpl_table_set_int(overscans, "xhig", nrows, nx);
15386 cpl_table_set_int(overscans, "yhig", nrows, ny);
15387 nrows++;
15388 }
15389 else {
15390 overscans = mos_load_overscans_vimos(header, 0);
15391 }
15392
15393 return overscans;
15394
15395 }
15396
15428 #define READY 1
15429 #ifdef READY
15430
15431 cpl_polynomial *mos_montecarlo_polyfit(cpl_table *points, cpl_table *evaluate,
15432 int samples, int order)
15433 {
15434
15435 const char *func = "mos_montecarlo_polyfit";
15436
15437 cpl_polynomial *p;
15438 cpl_polynomial *q;
15439 cpl_vector *listx;
15440 cpl_vector *listy;
15441 double err;
15442 double *x;
15443 double *px;
15444 double *x_eval;
15445 double *px_eval;
15446 double *sigma;
15447 double *vy;
15448 double *dy;
15449 int npoints, nevaluate;
15450 int i, j;
15451
15452
15453 if (points == NULL || evaluate == NULL) {
15454 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15455 return NULL;
15456 }
15457
15458 if (!cpl_table_has_column(points, "x")) {
15459 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15460 return NULL;
15461 }
15462
15463 if (cpl_table_get_column_type(points, "x") != CPL_TYPE_DOUBLE) {
15464 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15465 return NULL;
15466 }
15467
15468 if (cpl_table_has_invalid(points, "x")) {
15469 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15470 return NULL;
15471 }
15472
15473 if (!cpl_table_has_column(points, "y")) {
15474 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15475 return NULL;
15476 }
15477
15478 if (cpl_table_get_column_type(points, "y") != CPL_TYPE_DOUBLE) {
15479 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15480 return NULL;
15481 }
15482
15483 if (cpl_table_has_invalid(points, "y")) {
15484 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15485 return NULL;
15486 }
15487
15488 if (cpl_table_has_column(points, "y_err")) {
15489
15490 if (cpl_table_get_column_type(points, "y_err") != CPL_TYPE_DOUBLE) {
15491 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15492 return NULL;
15493 }
15494
15495 if (cpl_table_has_invalid(points, "y_err")) {
15496 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15497 return NULL;
15498 }
15499 }
15500
15501 if (!cpl_table_has_column(evaluate, "x")) {
15502 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15503 return NULL;
15504 }
15505
15506 if (cpl_table_get_column_type(evaluate, "x") != CPL_TYPE_DOUBLE) {
15507 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
15508 return NULL;
15509 }
15510
15511 if (cpl_table_has_invalid(evaluate, "x")) {
15512 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15513 return NULL;
15514 }
15515
15516 if (samples < 2 || order < 0) {
15517 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15518 return NULL;
15519 }
15520
15521 npoints = cpl_table_get_nrow(points);
15522 listx = cpl_vector_wrap(npoints, cpl_table_get_data_double(points, "x"));
15523 listy = cpl_vector_wrap(npoints, cpl_table_get_data_double(points, "y"));
15524
15525 p = cpl_polynomial_fit_1d_create(listx, listy, order, &err);
15526
15527 if (!cpl_table_has_column(points, "y_err")) {
15528 err = sqrt(err);
15529 cpl_table_new_column(points, "y_err", CPL_TYPE_DOUBLE);
15530 cpl_table_fill_column_window_double(points, "y_err", 0, npoints, err);
15531 cpl_msg_info(func, "Error column not found - set to %f\n", err);
15532 }
15533
15534
15535
15536
15537
15538 if (cpl_table_has_column(points, "px"))
15539 cpl_table_erase_column(points, "px");
15540 cpl_table_new_column(points, "px", CPL_TYPE_DOUBLE);
15541 cpl_table_fill_column_window_double(points, "px", 0, npoints, 0);
15542 x = cpl_table_get_data_double(points, "x");
15543 px = cpl_table_get_data_double(points, "px");
15544 for (i = 0; i < npoints; i++)
15545 px[i] = cpl_polynomial_eval_1d(p, x[i], NULL);
15546
15547 nevaluate = cpl_table_get_nrow(evaluate);
15548
15549 if (cpl_table_has_column(evaluate, "px"))
15550 cpl_table_erase_column(evaluate, "px");
15551 cpl_table_new_column(evaluate, "px", CPL_TYPE_DOUBLE);
15552 cpl_table_fill_column_window_double(evaluate, "px", 0, nevaluate, 0);
15553 x_eval = cpl_table_get_data_double(evaluate, "x");
15554 px_eval = cpl_table_get_data_double(evaluate, "px");
15555 for (i = 0; i < nevaluate; i++)
15556 px_eval[i] = cpl_polynomial_eval_1d(p, x_eval[i], NULL);
15557
15558
15559
15560
15561
15562 if (cpl_table_has_column(evaluate, "sigma"))
15563 cpl_table_erase_column(evaluate, "sigma");
15564 cpl_table_new_column(evaluate, "sigma", CPL_TYPE_DOUBLE);
15565 cpl_table_fill_column_window_double(evaluate, "sigma", 0, nevaluate, 0);
15566 sigma = cpl_table_get_data_double(evaluate, "sigma");
15567
15568
15569
15570
15571
15572 if (cpl_table_has_column(points, "vy"))
15573 cpl_table_erase_column(points, "vy");
15574 cpl_table_new_column(points, "vy", CPL_TYPE_DOUBLE);
15575 cpl_table_fill_column_window_double(points, "vy", 0, npoints, 0);
15576 vy = cpl_table_get_data_double(points, "vy");
15577 dy = cpl_table_get_data_double(points, "y_err");
15578 cpl_vector_unwrap(listy);
15579 listy = cpl_vector_wrap(npoints, vy);
15580
15581 for (i = 0; i < samples; i++) {
15582 for (j = 0; j < npoints; j++)
15583 vy[j] = px[j] + dy[j] * mos_randg(1);
15584 q = cpl_polynomial_fit_1d_create(listx, listy, order, NULL);
15585 for (j = 0; j < nevaluate; j++)
15586 sigma[j] += fabs(px_eval[j]
15587 - cpl_polynomial_eval_1d(q, x_eval[j], NULL));
15588 cpl_polynomial_delete(q);
15589 }
15590
15591
15592
15593
15594
15595 cpl_table_multiply_scalar(evaluate, "sigma", 1.25);
15596 cpl_table_divide_scalar(evaluate, "sigma", samples);
15597
15598 cpl_vector_unwrap(listx);
15599 cpl_vector_unwrap(listy);
15600
15601 return p;
15602 }
15603
15604 #endif
15605
15628 cpl_error_code mos_randomise_image(cpl_image *image, double ron,
15629 double gain, double bias)
15630 {
15631 float *data;
15632 int npix, i;
15633
15634
15635 if (image == NULL)
15636 return cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
15637
15638 if (ron < 0.0 || gain <= FLT_EPSILON)
15639 return cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
15640
15641 data = cpl_image_get_data_float(image);
15642 npix = cpl_image_get_size_x(image) * cpl_image_get_size_y(image);
15643 ron *= ron;
15644
15645 for (i = 0; i < npix; i++) {
15646 if (data[i] < bias) {
15647 data[i] += sqrt(ron) * mos_randg(1);
15648 }
15649 else {
15650 data[i] += sqrt(ron + (data[i] - bias) / gain) * mos_randg(1);
15651 }
15652 }
15653
15654 return CPL_ERROR_NONE;
15655 }
15656
15657
15672 cpl_error_code mos_refmask_find_gaps(cpl_mask *refmask,
15673 cpl_image *master_flat,
15674 double level)
15675 {
15676 int nx = cpl_mask_get_size_x(refmask);
15677 int ny = cpl_mask_get_size_y(refmask);
15678
15679 int * xpos = cpl_calloc(sizeof(int), ny);
15680
15681 cpl_image * filtered = cpl_image_duplicate(master_flat);
15682 cpl_mask * kernel = cpl_mask_new(9, 9);
15683 cpl_vector * v = cpl_vector_new(ny);
15684 cpl_vector * truev;
15685 int nvalid = 0;
15686 double * flats = cpl_vector_get_data(v);
15687
15688 double median, stdev, delta;
15689
15690 int i, kill;
15691
15692
15693 cpl_mask_not(kernel);
15694 cpl_image_filter_mask(filtered, master_flat, kernel,
15695 CPL_FILTER_MEDIAN, CPL_BORDER_COPY);
15696 cpl_mask_delete(kernel);
15697
15698 for (i = 1; i <= ny; i++) {
15699 int j = 0;
15700
15701 do j++;
15702 while (!cpl_mask_get(refmask, j, i) && j < nx);
15703
15704 if (j < nx) {
15705 int rejected;
15706
15707 xpos[i - 1] = j;
15708 flats[nvalid] = cpl_image_get(filtered, j, i, &rejected);
15709 nvalid++;
15710 }
15711 else {
15712 xpos[i - 1] = -1;
15713 }
15714 }
15715
15716 if (nvalid == 0)
15717 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
15718
15719 truev = cpl_vector_wrap(nvalid, flats);
15720
15721 median = cpl_vector_get_median(truev);
15722
15723 if (level < 0.0)
15724 stdev = cpl_vector_get_stdev(truev);
15725
15726 cpl_vector_unwrap(truev);
15727 cpl_vector_delete(v);
15728
15729 for (i = 1; i <= ny; i++) {
15730 if (xpos[i - 1] > 0) {
15731 int rejected;
15732 double kappa = 1.0;
15733
15734 delta = cpl_image_get(filtered, xpos[i - 1], i, &rejected) - median;
15735
15736 if (level < 0.0)
15737 kill = fabs(delta) > stdev * kappa;
15738 else
15739 kill = delta < level;
15740
15741 if (kill) {
15742 int j = 0;
15743
15744 while (cpl_mask_get(refmask, xpos[i - 1] + j, i)) {
15745 cpl_mask_set(refmask, xpos[i - 1] + j, i, CPL_BINARY_0);
15746 j++;
15747 }
15748 }
15749 }
15750 }
15751
15752 cpl_image_delete(filtered);
15753 cpl_free(xpos);
15754
15755 return cpl_error_get_code();
15756 }
15757
15765 cpl_error_code mos_saturation_process(cpl_image * image)
15766 {
15767 int nx = cpl_image_get_size_x(image);
15768 int ny = cpl_image_get_size_y(image);
15769 int npix = nx * ny;
15770 float * sdata = cpl_image_get_data_float(image);
15771
15772 int count, i, j, k;
15773
15774
15775
15776
15777
15778
15779
15780 for (i = 0; i < npix - nx; i++)
15781 if (sdata[i] == 0.0 && sdata[i + nx] == 0.0)
15782 sdata[i] = 65535.0;
15783
15784 for (i = npix - nx; i < npix; i++)
15785 if (sdata[i] == 0.0)
15786 sdata[i] = 65535.0;
15787
15788
15789
15790
15791
15792
15793
15794 for (i = 0; i < npix; i++) {
15795 if (sdata[i] >= 65535.0) {
15796 count = 0;
15797 for (j = i; j < npix; j++) {
15798 if (sdata[j] < 65535.0) {
15799 break;
15800 }
15801 else {
15802 count++;
15803 }
15804 }
15805 if (count < 30 && count > 2) {
15806 for (j = i; j < i + count/2; j++)
15807 sdata[j] = sdata[i] + 1000.0 * (j - i);
15808 if (count % 2 != 0) {
15809 sdata[j] = sdata[j-1] + 1000.0;
15810 j++;
15811 }
15812 for (k = j; k <= i + count; k++)
15813 sdata[k] = sdata[i] - 1000.0 * (k - i - count);
15814 i = k;
15815 }
15816 }
15817 }
15818
15819 return cpl_error_get_code();
15820 }
15821
15822
15831 cpl_error_code mos_subtract_background(cpl_image * image)
15832 {
15833
15834
15835
15836
15837 cpl_image * bimage = mos_arc_background(image, 15, 15);
15838 cpl_image_subtract(image, bimage);
15839 cpl_image_delete(bimage);
15840
15841 return cpl_error_get_code();
15842 }
15843
15844
15861 cpl_error_code mos_object_intersect(cpl_table **slitss, cpl_table *origslits,
15862 int nscience, float tolerance)
15863 {
15864 int i, j;
15865
15866 cpl_table *summary;
15867 int summary_nobjs = 0;
15868
15869 int nobjs;
15870
15871 int nmatches;
15872 int nslits = cpl_table_get_nrow(slitss[0]);
15873
15874 int maxobjs;
15875 int k, m;
15876 int nstokes, sstokes;
15877
15878 cpl_table **work;
15879
15880 work = (cpl_table **)cpl_malloc(sizeof(cpl_table *) * nscience);
15881
15882
15883
15884
15885
15886
15887
15888
15889
15890
15891 for (j = 0; j < nscience; j++) {
15892 int c_nobjs = mos_get_nobjects(slitss[j]);
15893 if (!c_nobjs)
15894 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
15895 summary_nobjs += c_nobjs;
15896 }
15897
15898 summary = cpl_table_new(summary_nobjs);
15899
15900 cpl_table_new_column(summary, "offset", CPL_TYPE_DOUBLE);
15901 cpl_table_new_column(summary, "pair", CPL_TYPE_INT);
15902 cpl_table_new_column(summary, "absolute", CPL_TYPE_DOUBLE);
15903 cpl_table_new_column(summary, "pos", CPL_TYPE_DOUBLE);
15904
15905
15906
15907
15908
15909 nobjs = 0;
15910
15911
15912 for (j = 0; j < nscience; j++) {
15913 int c_maxobjs = mos_get_maxobjs_per_slit(slitss[j]);
15914
15915
15916 for (k = 0; k < nslits; k++) {
15917
15918
15919 for (m = 0; m < c_maxobjs; m++) {
15920 int null;
15921 char *name = cpl_sprintf("object_%d", m + 1);
15922 double obj = cpl_table_get_double(slitss[j], name, k, &null);
15923 int pos;
15924 int pair;
15925
15926 cpl_free(name);
15927
15928 if (null)
15929 break;
15930
15931
15932
15933
15934
15935
15936
15937
15938 pos = cpl_table_get_int(slitss[j], "position", k, &null);
15939 pair = cpl_table_get_int(slitss[j], "pair_id", k, &null);
15940 cpl_table_set(summary, "absolute", nobjs, obj);
15941 cpl_table_set(summary, "pos", nobjs, pos);
15942 cpl_table_set(summary, "offset", nobjs, obj - pos);
15943 cpl_table_set(summary, "pair", nobjs, pair);
15944
15945 nobjs++;
15946 }
15947 }
15948 }
15949
15950
15951
15952
15953
15954
15955
15956
15957
15958
15959 nmatches = 0;
15960 maxobjs = mos_get_maxobjs_per_slit(slitss[0]);
15961
15962
15963
15964
15965
15966
15967
15968
15969
15970
15971
15972
15973 for (k = 0; k < nslits; k+=2) {
15974 int slitmatches = 0;
15975
15976 if (k == 0) {
15977 if (cpl_table_get_int(slitss[0], "pair_id", 0, NULL) !=
15978 cpl_table_get_int(slitss[0], "pair_id", 1, NULL)) {
15979
15980
15981
15982
15983
15984 k++;
15985 continue;
15986 }
15987 }
15988
15989 for (m = 0; m < maxobjs; m++) {
15990 int null;
15991 char *name = cpl_sprintf("object_%d", m + 1);
15992 double obj = cpl_table_get_double(slitss[0], name, k, &null);
15993 double pos;
15994 int pair;
15995
15996 char *name_obj = NULL;
15997 char *name_start = NULL;
15998 char *name_end = NULL;
15999 char *name_row = NULL;
16000 char *name_row_s = NULL;
16001
16002 char *name_start_o = NULL;
16003 char *name_end_o = NULL;
16004 char *name_row_o = NULL;
16005 char *name_start_v = NULL;
16006 char *name_end_v = NULL;
16007 char *name_obj_v = NULL;
16008
16009 int start, end;
16010 int length;
16011
16012 int selected;
16013 int v, start_v, end_v;
16014 double min_v, obj_v;
16015
16016
16017 cpl_free(name);
16018
16019 if (null)
16020 break;
16021
16022
16023
16024
16025
16026
16027
16028
16029 pos = cpl_table_get_int(slitss[0], "position", k, &null);
16030 pair = cpl_table_get_int(slitss[0], "pair_id", k, &null);
16031
16032
16033
16034
16035
16036
16037
16038
16039 cpl_table_select_all(summary);
16040
16041 cpl_table_and_selected_int(summary, "pair", CPL_EQUAL_TO, pair);
16042 cpl_table_and_selected_double(summary, "offset", CPL_LESS_THAN,
16043 obj - pos + tolerance);
16044 selected =
16045 cpl_table_and_selected_double(summary, "offset", CPL_GREATER_THAN,
16046 obj - pos - tolerance);
16047
16048
16049
16050
16051
16052
16053
16054
16055
16056 if (selected != nscience * 2)
16057 continue;
16058
16059
16060
16061
16062
16063
16064
16065 slitmatches++;
16066
16067
16068
16069
16070
16071
16072
16073
16074
16075
16076
16077 name_obj = cpl_sprintf("object_%d", slitmatches);
16078 name_start = cpl_sprintf("start_%d", slitmatches);
16079 name_end = cpl_sprintf("end_%d", slitmatches);
16080 name_row = cpl_sprintf("row_%d", slitmatches);
16081 name_row_s = cpl_sprintf("row_stokes_%d", slitmatches);
16082
16083
16084
16085
16086
16087
16088 name_start_o = cpl_sprintf("start_%d", m + 1);
16089 name_end_o = cpl_sprintf("end_%d", m + 1);
16090 name_row_o = cpl_sprintf("row_%d", m + 1);
16091
16092
16093
16094
16095
16096 if (!cpl_table_has_column(origslits, name_obj)) {
16097 cpl_table_new_column(origslits, name_obj, CPL_TYPE_DOUBLE);
16098 cpl_table_new_column(origslits, name_start, CPL_TYPE_INT);
16099 cpl_table_new_column(origslits, name_end, CPL_TYPE_INT);
16100 cpl_table_new_column(origslits, name_row, CPL_TYPE_INT);
16101 cpl_table_new_column(origslits, name_row_s, CPL_TYPE_INT);
16102 }
16103
16104
16105
16106
16107
16108
16109
16110
16111 length = cpl_table_get_int(origslits, "length", k + 1, &null);
16112
16113
16114
16115
16116
16117
16118
16119 for (v = 0; v < maxobjs; v++) {
16120 char *name_v = cpl_sprintf("object_%d", v + 1);
16121 double obj_v = cpl_table_get_double(slitss[0], name_v,
16122 k + 1, &null);
16123
16124 cpl_free(name_v);
16125
16126 if (null)
16127 break;
16128
16129 if (v) {
16130 if (fabs(obj - length - obj_v) < min_v) {
16131 min_v = fabs(obj - length - obj_v);
16132 cpl_free(name_start_v);
16133 cpl_free(name_end_v);
16134 cpl_free(name_obj_v);
16135 name_start_v = cpl_sprintf("start_%d", v + 1);
16136 name_end_v = cpl_sprintf("end_%d", v + 1);
16137 name_obj_v = cpl_sprintf("object_%d", v + 1);
16138 }
16139 }
16140 else {
16141 min_v = fabs(obj - length - obj_v);
16142 name_start_v = cpl_sprintf("start_%d", v + 1);
16143 name_end_v = cpl_sprintf("end_%d", v + 1);
16144 name_obj_v = cpl_sprintf("object_%d", v + 1);
16145 }
16146 }
16147
16148
16149
16150
16151
16152
16153 start = cpl_table_get_int(slitss[0], name_start_o, k, &null);
16154 end = cpl_table_get_int(slitss[0], name_end_o, k, &null);
16155
16156
16157
16158
16159
16160 start_v = cpl_table_get_int(slitss[0], name_start_v, k + 1, &null);
16161 end_v = cpl_table_get_int(slitss[0], name_end_v, k + 1, &null);
16162 obj_v = cpl_table_get_double(slitss[0], name_obj_v, k + 1, &null);
16163
16164
16165
16166
16167
16168
16169
16170
16171
16172
16173 cpl_table_set_double(origslits, name_obj, k, obj);
16174 cpl_table_set_double(origslits, name_obj, k + 1, obj_v);
16175
16176
16177 cpl_table_set_int(origslits, name_start, k, start);
16178 cpl_table_set_int(origslits, name_start, k + 1, start_v);
16179
16180
16181 cpl_table_set_int(origslits, name_end, k, end);
16182 cpl_table_set_int(origslits, name_end, k + 1, end_v);
16183
16184
16185
16186
16187
16188
16189
16190
16191
16192
16193
16194
16195
16196
16197 cpl_table_set_int(origslits, name_row, k, nmatches);
16198 nmatches++;
16199 cpl_table_set_int(origslits, name_row, k + 1, nmatches);
16200 nmatches++;
16201
16202 cpl_free(name_obj);
16203 cpl_free(name_start);
16204 cpl_free(name_end);
16205 cpl_free(name_row);
16206 cpl_free(name_row_s);
16207
16208 cpl_free(name_start_o);
16209 cpl_free(name_end_o);
16210 cpl_free(name_row_o);
16211
16212 cpl_free(name_start_v); name_start_v = NULL;
16213 cpl_free(name_end_v); name_end_v = NULL;
16214 cpl_free(name_obj_v); name_obj_v = NULL;
16215 }
16216 }
16217
16218
16219
16220
16221
16222
16223 cpl_table_delete(summary);
16224
16225 if (!nmatches)
16226 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
16227
16228
16229
16230
16231
16232
16233
16234
16235
16236
16237
16238 maxobjs = mos_get_maxobjs_per_slit(origslits);
16239 nstokes = nmatches / 2;
16240
16241 for (k = 0; k < nslits; k++) {
16242 if (k % 2) {
16243 nstokes = sstokes;
16244 }
16245 else {
16246 sstokes = nstokes;
16247 }
16248
16249 for (m = 0; m < maxobjs; m++) {
16250 char *name = cpl_sprintf("row_%d", m + 1);
16251 char *namestokes = cpl_sprintf("row_stokes_%d", m + 1);
16252
16253 if (!cpl_table_is_valid(origslits, name, k)) {
16254 cpl_free(name);
16255 cpl_free(namestokes);
16256 break;
16257 }
16258 else {
16259 nmatches--;
16260 nstokes--;
16261 cpl_table_set_int(origslits, name, k, nmatches);
16262 cpl_table_set_int(origslits, namestokes, k, nstokes);
16263 }
16264
16265 cpl_free(name);
16266 cpl_free(namestokes);
16267 }
16268 }
16269
16270
16271
16272
16273
16274
16275
16276
16277
16278 for (j = 0; j < maxobjs; j++) {
16279 char *name = cpl_sprintf("object_%d", j + 1);
16280 cpl_table_fill_invalid_double(origslits, name, -1);
16281 cpl_free(name);
16282
16283 name = cpl_sprintf("start_%d", j + 1);
16284 cpl_table_fill_invalid_int(origslits, name, -1);
16285 cpl_free(name);
16286
16287 name = cpl_sprintf("end_%d", j + 1);
16288 cpl_table_fill_invalid_int(origslits, name, -1);
16289 cpl_free(name);
16290
16291 name = cpl_sprintf("row_%d", j + 1);
16292 cpl_table_fill_invalid_int(origslits, name, -1);
16293 cpl_free(name);
16294
16295 name = cpl_sprintf("row_stokes_%d", j + 1);
16296 cpl_table_fill_invalid_int(origslits, name, -1);
16297 cpl_free(name);
16298 }
16299
16300
16301
16302
16303
16304
16305
16306
16307
16308
16309
16310
16311 for (i = 0; i < nscience; i++) {
16312 int c_maxobjs = mos_get_maxobjs_per_slit(slitss[i]);
16313
16314 work[i] = cpl_table_duplicate(slitss[i]);
16315
16316 for (m = 0; m < c_maxobjs; m++) {
16317 char *object_o = cpl_sprintf("object_%d", m + 1);
16318 char *start_o = cpl_sprintf("start_%d", m + 1);
16319 char *end_o = cpl_sprintf("end_%d", m + 1);
16320 char *row_o = cpl_sprintf("row_%d", m + 1);
16321
16322 cpl_table_erase_column(slitss[i], object_o);
16323 cpl_table_erase_column(slitss[i], start_o);
16324 cpl_table_erase_column(slitss[i], end_o);
16325 cpl_table_erase_column(slitss[i], row_o);
16326 }
16327 }
16328
16329
16330
16331
16332
16333 for (k = 0; k < nslits; k++) {
16334 for (j = 0; j < maxobjs; j++) {
16335 double object_w, object_r;
16336 int start_w, start_r;
16337 int end_w, end_r;
16338 int row_w, row_r;
16339
16340 char *object_i = cpl_sprintf("object_%d", j + 1);
16341 char *start_i = cpl_sprintf("start_%d", j + 1);
16342 char *end_i = cpl_sprintf("end_%d", j + 1);
16343 char *row_i = cpl_sprintf("row_%d", j + 1);
16344
16345
16346 if (!cpl_table_is_valid(origslits, object_i, k))
16347 break;
16348
16349
16350
16351
16352
16353
16354
16355
16356
16357
16358
16359 object_w = cpl_table_get_double(origslits, object_i, k, NULL);
16360 start_w = cpl_table_get_int (origslits, start_i, k, NULL);
16361 end_w = cpl_table_get_int (origslits, end_i, k, NULL);
16362 row_w = cpl_table_get_int (origslits, row_i, k, NULL);
16363
16364 for (i = 0; i < nscience; i++) {
16365 int c_maxobjs = mos_get_maxobjs_per_slit(work[i]);
16366 int minpos;
16367 double mindiff, diff;
16368 char *object_o;
16369 char *start_o;
16370 char *end_o;
16371 char *row_o;
16372
16373 for (m = 0; m < c_maxobjs; m++) {
16374 object_o = cpl_sprintf("object_%d", m + 1);
16375 start_o = cpl_sprintf("start_%d", m + 1);
16376 end_o = cpl_sprintf("end_%d", m + 1);
16377 row_o = cpl_sprintf("row_%d", m + 1);
16378
16379 if (!cpl_table_is_valid(work[i], object_o, k))
16380 break;
16381
16382 object_r = cpl_table_get_double(work[i], object_o, k, NULL);
16383 start_r = cpl_table_get_int (work[i], start_o, k, NULL);
16384 end_r = cpl_table_get_int (work[i], end_o, k, NULL);
16385 row_r = cpl_table_get_int (work[i], row_o, k, NULL);
16386
16387 diff = fabs(object_w - object_r);
16388 if (m) {
16389 if (mindiff > diff) {
16390 mindiff = diff;
16391 minpos = m;
16392 }
16393 }
16394 else {
16395 mindiff = diff;
16396 minpos = 0;
16397 }
16398
16399 cpl_free(object_o);
16400 cpl_free(start_o);
16401 cpl_free(end_o);
16402 cpl_free(row_o);
16403 }
16404
16405 object_o = cpl_sprintf("object_%d", minpos + 1);
16406 start_o = cpl_sprintf("start_%d", minpos + 1);
16407 end_o = cpl_sprintf("end_%d", minpos + 1);
16408 row_o = cpl_sprintf("row_%d", minpos + 1);
16409
16410 if (!cpl_table_has_column(slitss[i], object_i)) {
16411 cpl_table_new_column(slitss[i], object_i, CPL_TYPE_DOUBLE);
16412 cpl_table_new_column(slitss[i], start_i, CPL_TYPE_INT);
16413 cpl_table_new_column(slitss[i], end_i, CPL_TYPE_INT);
16414 cpl_table_new_column(slitss[i], row_i, CPL_TYPE_INT);
16415 cpl_table_fill_invalid_double(slitss[i], object_i, -1);
16416 cpl_table_fill_invalid_int (slitss[i], start_i, -1);
16417 cpl_table_fill_invalid_int (slitss[i], end_i, -1);
16418 cpl_table_fill_invalid_int (slitss[i], row_i, -1);
16419 }
16420
16421 cpl_table_set_double(slitss[i], object_i, k,
16422 cpl_table_get_double(work[i], object_o,
16423 k, NULL));
16424 cpl_table_set_int(slitss[i], start_i , k,
16425 cpl_table_get_int(work[i], start_o, k, NULL));
16426 cpl_table_set_int(slitss[i], end_i , k,
16427 cpl_table_get_int(work[i], end_o, k, NULL));
16428 cpl_table_set_int(slitss[i], row_i , k, row_w);
16429
16430 cpl_free(object_o);
16431 cpl_free(start_o);
16432 cpl_free(end_o);
16433 cpl_free(row_o);
16434 }
16435
16436 cpl_free(object_i);
16437 cpl_free(start_i);
16438 cpl_free(end_i);
16439 cpl_free(row_i);
16440 }
16441 }
16442
16443 for (i = 0; i < nscience; i++)
16444 cpl_table_delete(work[i]);
16445
16446 cpl_free(work);
16447
16448
16449 return cpl_error_get_code();
16450 }
16451
16452
16460 int mos_get_maxobjs_per_slit(cpl_table * slits)
16461 {
16462 int maxobjs = 1;
16463
16464 char * colname = cpl_sprintf("object_%d", maxobjs);
16465
16466 while (cpl_table_has_column(slits, colname)) {
16467 maxobjs++;
16468 cpl_free(colname);
16469 colname = cpl_sprintf("object_%d", maxobjs);
16470 }
16471
16472 cpl_free(colname);
16473
16474 maxobjs--;
16475
16476 return maxobjs;
16477 }
16478
16486 int mos_get_nobjects(cpl_table * slits)
16487 {
16488 int nobjs = 0;
16489
16490 int nslits = cpl_table_get_nrow(slits);
16491 int maxobjs = mos_get_maxobjs_per_slit(slits);
16492
16493 int k, m;
16494
16495 for (k = 0; k < nslits; k++) {
16496 for (m = 0; m < maxobjs; m++) {
16497 char * name = cpl_sprintf("object_%d", m + 1);
16498 int null = !cpl_table_is_valid(slits, name, k);
16499
16500 cpl_free(name);
16501
16502 if (null) break;
16503 else nobjs++;
16504 }
16505 }
16506
16507 return nobjs;
16508 }
16509
16517 int mos_check_slits(cpl_table *slits, float rescale)
16518 {
16519
16520 cpl_propertylist *sort;
16521
16522 int nslits = cpl_table_get_nrow(slits);
16523
16524 int k, null;
16525
16526 const float interval = 90.0 * rescale;
16527 const float offset = (90.0 - 5) * rescale;
16528
16529
16530 for (k = 0; k < nslits; k++) {
16531 double ytop = cpl_table_get_double(slits, "ytop", k, &null);
16532 double ybottom = cpl_table_get_double(slits, "ybottom", k, &null);
16533
16534 double xtop = cpl_table_get_double(slits, "xtop", k, &null);
16535 double xbottom = cpl_table_get_double(slits, "xbottom", k, &null);
16536
16537 int nmiss = (int)((ytop - ybottom) / interval + 0.5);
16538
16539 if (nmiss > 1) {
16540 cpl_msg_warning(cpl_func,
16541 "Some slits could not be properly detected. "
16542 "There might be accountable inaccuracies.");
16543 while (nmiss > 1) {
16544 cpl_table_set_size(slits, nslits + 1);
16545
16546
16547
16548
16549 cpl_table_set_double(slits, "xtop", nslits, xtop);
16550 cpl_table_set_double(slits, "xbottom", nslits, xbottom);
16551
16552
16553 if (k == 0) {
16554 cpl_table_set_double(slits, "ybottom", nslits, ybottom);
16555 cpl_table_set_double(slits, "ytop", nslits, ybottom
16556 + offset);
16557 ybottom += interval;
16558 cpl_table_set_double(slits, "ybottom", k, ybottom);
16559 } else {
16560 cpl_table_set_double(slits, "ytop", nslits, ytop);
16561 cpl_table_set_double(slits, "ybottom", nslits, ytop
16562 - offset);
16563 ytop -= interval;
16564 cpl_table_set_double(slits, "ytop", k, ytop);
16565 }
16566
16567 nslits++; nmiss--;
16568 }
16569 }
16570 }
16571
16572 sort = cpl_propertylist_new();
16573 cpl_propertylist_append_bool(sort, "ytop", 1);
16574 cpl_table_sort(slits, sort);
16575 cpl_propertylist_delete(sort);
16576
16577
16578
16579
16580
16581
16582 k = cpl_table_get_nrow(slits) - 1;
16583
16584 {
16585 double ytop = cpl_table_get_double(slits, "ytop", k, &null);
16586 double ybottom = cpl_table_get_double(slits, "ybottom", k, &null);
16587 double length = (ytop - ybottom) / interval;
16588
16589 if (length > 1.1) {
16590 cpl_table_set_double(slits, "ybottom", k, ytop - offset);
16591 }
16592
16593 }
16594
16595 return 0;
16596 }
16597
16620 cpl_table *mos_load_slits_fors_pmos(cpl_propertylist *header)
16621 {
16622 int m, null;
16623 int halfsize;
16624
16625 cpl_propertylist * sort;
16626 cpl_table * slits;
16627
16628 slits = mos_load_slits_fors_mos(header);
16629 halfsize = cpl_table_get_nrow(slits);
16630
16631 cpl_table_set_size(slits, 2 * halfsize);
16632
16633 for (m = 0; m < halfsize; m++) {
16634
16635 double gap = 1.4;
16636
16637 double length =
16638 cpl_table_get(slits, "ytop", m, &null) -
16639 cpl_table_get(slits, "ybottom", m, &null);
16640
16641 if (m) {
16642 double interval =
16643 cpl_table_get(slits, "ybottom", m - 1, &null) -
16644 cpl_table_get(slits, "ytop", m, &null);
16645
16646 gap = (interval - length) / 2;
16647 }
16648
16649 cpl_table_set(slits, "slit_id", m + halfsize,
16650 cpl_table_get(slits, "slit_id", m, &null) - 1);
16651
16652 cpl_table_set(slits, "xtop", m + halfsize,
16653 cpl_table_get(slits, "xtop", m, &null));
16654
16655 cpl_table_set(slits, "xbottom", m + halfsize,
16656 cpl_table_get(slits, "xbottom", m, &null));
16657
16658 cpl_table_set(slits, "ytop", m + halfsize,
16659 cpl_table_get(slits, "ytop", m, &null) + gap + length);
16660
16661 cpl_table_set(slits, "ybottom", m + halfsize,
16662 cpl_table_get(slits, "ytop", m, &null) + gap);
16663 }
16664
16665 for (m = 0; m < 2 * halfsize; m++) {
16666 cpl_table_set(slits, "ytop", m,
16667 cpl_table_get(slits, "ytop", m, &null) - 5.3);
16668
16669 cpl_table_set(slits, "ybottom", m,
16670 cpl_table_get(slits, "ybottom", m, &null) - 5.3);
16671
16672 }
16673
16674 sort = cpl_propertylist_new();
16675 cpl_propertylist_append_bool(sort, "ytop", 1);
16676 cpl_table_sort(slits, sort);
16677
16678 cpl_propertylist_delete(sort);
16679
16680 return slits;
16681 }
16682
16683 int * fors_get_nobjs_perslit(cpl_table * slits)
16684 {
16685 int nslits = cpl_table_get_nrow(slits);
16686 int maxobjs = mos_get_maxobjs_per_slit(slits);
16687
16688 int * nobjs_per_slit = cpl_malloc(sizeof(int) * nslits);
16689
16690 int k, m;
16691
16692 for (k = 0; k < nslits; k++) {
16693 int nobjs = 0;
16694 for (m = 0; m < maxobjs; m++) {
16695 char * name = cpl_sprintf("object_%d", m + 1);
16696 int null = !cpl_table_is_valid(slits, name, k);
16697
16698 cpl_free(name);
16699
16700 if (null) break;
16701 else nobjs++;
16702 }
16703
16704 nobjs_per_slit[k] = nobjs;
16705 }
16706
16707 return nobjs_per_slit;
16708 }
16709
16710 double fors_get_object_position(cpl_table *slits, int slit, int object)
16711 {
16712 char *name = cpl_sprintf("object_%d", object);
16713 double position;
16714
16715 position = cpl_table_get_double(slits, name, slit, NULL)
16716 - cpl_table_get_int(slits, "position", slit, NULL);
16717
16718 cpl_free(name);
16719
16720 return position;
16721 }
16722
16723 int mos_rebin_signal(cpl_image **image, int rebin)
16724 {
16725 cpl_image *rebinned;
16726
16727
16728 if (*image == NULL)
16729 return 1;
16730
16731 if (rebin == 1)
16732 return 0;
16733
16734 rebinned = cpl_image_rebin(*image, 1, 1, rebin, 1);
16735
16736 cpl_image_delete(*image);
16737
16738 *image = rebinned;
16739
16740 return 0;
16741 }
16742
16743 int mos_rebin_error(cpl_image **image, int rebin)
16744 {
16745 if (*image == NULL)
16746 return 1;
16747
16748 if (rebin == 1)
16749 return 0;
16750
16751 cpl_image_power(*image, 2);
16752 mos_rebin_signal(image, rebin);
16753 cpl_image_power(*image, 0.5);
16754
16755 return 0;
16756 }
16757
16758
16759
16760
16761
16762
16763
16764
16765
16766
16767
16768
16769
16770
16771
16772
16773
16774
16775 int map_table(cpl_image *image, double start, double step,
16776 cpl_table *table, char *xname, char *yname)
16777 {
16778 int length = cpl_image_get_size_x(image);
16779 int nrows = cpl_table_get_nrow(table);
16780 float *data = cpl_image_get_data_float(image);
16781 float *fdata = NULL;
16782 double *xdata = NULL;
16783 double *ydata = NULL;
16784 cpl_type xtype = cpl_table_get_column_type(table, xname);
16785 cpl_type ytype = cpl_table_get_column_type(table, yname);
16786 double xzero, pos;
16787 int i, j, n;
16788
16789
16790
16791
16792
16793
16794
16795 for (i = 0; i < length; i++)
16796 data[i] = 0.0;
16797
16798
16799
16800
16801
16802
16803 if (xtype == CPL_TYPE_FLOAT) {
16804 fdata = cpl_table_get_data_float(table, xname);
16805 xdata = cpl_malloc(nrows * sizeof(double));
16806 for (i = 0; i < nrows; i++) {
16807 xdata[i] = fdata[i];
16808 }
16809 }
16810 else {
16811 xdata = cpl_table_get_data_double(table, xname);
16812 }
16813
16814 if (ytype == CPL_TYPE_FLOAT) {
16815 fdata = cpl_table_get_data_float(table, yname);
16816 ydata = cpl_malloc(nrows * sizeof(double));
16817 for (i = 0; i < nrows; i++) {
16818 ydata[i] = fdata[i];
16819 }
16820 }
16821 else {
16822 ydata = cpl_table_get_data_double(table, yname);
16823 }
16824
16825
16826
16827
16828
16829 n = 0;
16830 xzero = xdata[n];
16831
16832 for (i = 0; i < length; i++) {
16833 pos = start + step * i;
16834 if (pos < xzero)
16835 continue;
16836 for (j = n; j < nrows; j++) {
16837 if (xdata[j] > pos) {
16838 n = j;
16839 data[i] = ydata[j-1]
16840 + (ydata[j] - ydata[j-1])
16841 * (pos - xdata[j-1]) / (xdata[j] - xdata[j-1]);
16842 break;
16843 }
16844 }
16845 }
16846
16847 if (xtype == CPL_TYPE_FLOAT)
16848 cpl_free(xdata);
16849
16850 if (ytype == CPL_TYPE_FLOAT)
16851 cpl_free(ydata);
16852
16853 return 0;
16854 }
16855
16856
16857
16858
16859
16860
16861
16862
16863
16864
16865
16866
16867
16868
16869
16870 static cpl_image *polysmooth(cpl_image *image, int order, int hw)
16871 {
16872 int npoints;
16873 cpl_vector *x;
16874 cpl_vector *y;
16875 double *xdata;
16876 double *ydata;
16877 cpl_polynomial *poly;
16878 cpl_vector *ysmooth;
16879 cpl_image *smoothed;
16880 float *sdata;
16881 int i;
16882
16883
16884 npoints = cpl_image_get_size_x(image);
16885
16886 if (2 * hw + 1 > npoints)
16887 return NULL;
16888
16889 x = cpl_vector_new(npoints);
16890 y = cpl_vector_new(npoints);
16891 xdata = cpl_vector_get_data(x);
16892 ydata = cpl_vector_get_data(y);
16893
16894 smoothed = cpl_image_duplicate(image);
16895 sdata = cpl_image_get_data_float(smoothed);
16896
16897 for (i = 0; i < npoints; i++) {
16898 xdata[i] = i;
16899 ydata[i] = sdata[i];
16900 }
16901
16902 ysmooth = cpl_vector_filter_median_create(y, hw);
16903 cpl_vector_delete(y);
16904
16905 poly = cpl_polynomial_fit_1d_create(x, ysmooth, order, NULL);
16906 cpl_vector_delete(x);
16907 cpl_vector_delete(ysmooth);
16908
16909 if (poly) {
16910 for (i = 0; i < npoints; i++)
16911 sdata[i] = cpl_polynomial_eval_1d(poly, i, NULL);
16912
16913 cpl_polynomial_delete(poly);
16914 }
16915 else {
16916 cpl_image_delete(smoothed);
16917 return NULL;
16918 }
16919
16920 return smoothed;
16921 }
16922
16923 #undef cleanup
16924 #define cleanup \
16925 do { \
16926 cpl_image_delete(spectrum); \
16927 cpl_image_delete(flux); \
16928 cpl_image_delete(efficiency); \
16929 cpl_image_delete(smo_efficiency); \
16930 cpl_image_delete(extinction); \
16931 cpl_image_delete(response); \
16932 cpl_image_delete(smo_response); \
16933 cpl_image_delete(physical); \
16934 } while (0)
16935
16959 cpl_table *mos_photometric_calibration(cpl_image *spectra, double startwave,
16960 double dispersion, double gain,
16961 double exptime, cpl_table *ext_table,
16962 double airmass, cpl_table *flux_table,
16963 int order)
16964 {
16965
16966 cpl_image *spectrum = NULL;
16967 float *data;
16968 cpl_image *extinction = NULL;
16969 float *ext_data;
16970 cpl_image *flux = NULL;
16971 float *flux_data;
16972 cpl_image *physical = NULL;
16973 float *phys_data;
16974 cpl_image *efficiency = NULL;
16975 float *eff_data;
16976 cpl_image *smo_efficiency = NULL;
16977 float *smo_eff_data;
16978 cpl_image *response = NULL;
16979 float *res_data;
16980 cpl_image *smo_response = NULL;
16981 float *smo_res_data;
16982 cpl_image *image;
16983 cpl_image *smo_image;
16984 cpl_table *table;
16985 float lambda;
16986 int nx, ny;
16987 int ext_count, ext_pos;
16988 int eff_count, eff_pos;
16989 int flux_count, flux_pos;
16990 int start, end;
16991 int i;
16992
16993
16994 if (spectra == NULL || ext_table == NULL || flux_table == NULL) {
16995 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
16996 return NULL;
16997 }
16998
16999 if (!cpl_table_has_column(ext_table, "WAVE")) {
17000 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17001 "Column WAVE in atmospheric extinction table");
17002 return NULL;
17003 }
17004
17005 if (!cpl_table_has_column(ext_table, "EXTINCTION")) {
17006 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17007 "Column EXTINCTION in atmospheric extinction table");
17008 return NULL;
17009 }
17010
17011 if (!cpl_table_has_column(flux_table, "WAVE")) {
17012 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17013 "Column WAVE in standard star flux table");
17014 return NULL;
17015 }
17016
17017 if (!cpl_table_has_column(flux_table, "FLUX")) {
17018 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17019 "Column FLUX in standard star flux table");
17020 return NULL;
17021 }
17022
17023 if (gain < 0.1) {
17024 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17025 "Invalid gain factor (%.2f)", gain);
17026 return NULL;
17027 }
17028
17029 if (exptime < 0.001) {
17030 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17031 "Invalid exposure time (%.2f)", exptime);
17032 return NULL;
17033 }
17034
17035 if (dispersion < 0.001) {
17036 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17037 "Invalid dispersion (%.2f)", dispersion);
17038 return NULL;
17039 }
17040
17041 if (order < 2) {
17042 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17043 "Order of the polynomial fitting the "
17044 "instrument response must be at least 2");
17045 return NULL;
17046 }
17047
17048 nx = cpl_image_get_size_x(spectra);
17049 ny = cpl_image_get_size_y(spectra);
17050
17051
17052
17053
17054
17055
17056 if (ny == 1) {
17057 spectrum = cpl_image_duplicate(spectra);
17058 }
17059 else {
17060 int x, y;
17061 cpl_image *brights = cpl_image_collapse_create(spectra, 1);
17062
17063 cpl_image_get_maxpos(brights, &x, &y);
17064 cpl_image_delete(brights);
17065 spectrum = cpl_image_extract(spectra, 1, y, nx, y);
17066 }
17067
17068
17069
17070
17071
17072
17073 cpl_image_multiply_scalar(spectrum, gain / exptime / dispersion);
17074
17075
17076
17077
17078
17079
17080
17081 extinction = cpl_image_duplicate(spectrum);
17082 map_table(extinction, startwave + dispersion/2, dispersion,
17083 ext_table, "WAVE", "EXTINCTION");
17084
17085
17086
17087
17088
17089
17090 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
17091 cpl_image_exponential(extinction, 10.);
17092
17093
17094
17095
17096
17097
17098 cpl_image_multiply(spectrum, extinction);
17099
17100
17101
17102
17103
17104
17105
17106 ext_data = cpl_image_get_data_float(extinction);
17107
17108 ext_count = 0;
17109 ext_pos = 0;
17110 for (i = 0; i < nx; i++) {
17111 if (ext_data[i] > 0.0) {
17112 if (ext_count == 0) {
17113 ext_pos = i;
17114 }
17115 ext_count++;
17116 }
17117 else {
17118 if (ext_count) {
17119 break;
17120 }
17121 }
17122 }
17123
17124 cpl_image_delete(extinction); extinction = NULL;
17125
17126
17127
17128
17129
17130
17131
17132 flux = cpl_image_duplicate(spectrum);
17133 map_table(flux, startwave + dispersion/2, dispersion,
17134 flux_table, "WAVE", "FLUX");
17135
17136
17137
17138
17139
17140
17141
17142 flux_data = cpl_image_get_data_float(flux);
17143
17144 flux_count = 0;
17145 flux_pos = 0;
17146 for (i = 0; i < nx; i++) {
17147 if (flux_data[i] > 0.0) {
17148 if (flux_count == 0) {
17149 flux_pos = i;
17150 }
17151 flux_count++;
17152 }
17153 else {
17154 if (flux_count) {
17155 break;
17156 }
17157 }
17158 }
17159
17160
17161
17162
17163
17164
17165 start = ext_pos > flux_pos ? ext_pos : flux_pos;
17166 end = (ext_pos + ext_count) < (flux_pos + flux_count) ?
17167 (ext_pos + ext_count) : (flux_pos + flux_count);
17168 flux_pos = start;
17169 flux_count = end - start;
17170
17171
17172
17173
17174
17175
17176
17177
17178
17179
17180 physical = cpl_image_duplicate(spectrum);
17181 phys_data = cpl_image_get_data_float(physical);
17182
17183 for (i = 0; i < nx; i++) {
17184 lambda = startwave + dispersion * (i + 0.5);
17185 phys_data[i] = 0.0026 * lambda * flux_data[i];
17186 }
17187
17188 efficiency = cpl_image_duplicate(spectrum);
17189 eff_data = cpl_image_get_data_float(efficiency);
17190 data = cpl_image_get_data_float(spectrum);
17191
17192 for (i = 0; i < nx; i++) {
17193 if (phys_data[i] > 0.0)
17194 eff_data[i] = data[i] / phys_data[i];
17195 else
17196 eff_data[i] = 0.0;
17197 }
17198
17199 cpl_image_delete(physical); physical = NULL;
17200
17201
17202
17203
17204
17205
17206
17207 eff_count = 0;
17208 eff_pos = 0;
17209 for (i = 0; i < nx; i++) {
17210 if (eff_data[i] > 0.01) {
17211 if (eff_count == 0) {
17212 eff_pos = i;
17213 }
17214 eff_count++;
17215 }
17216 else {
17217 if (eff_count > 300) {
17218 break;
17219 }
17220 }
17221 }
17222
17223
17224
17225
17226
17227
17228 start = eff_pos > flux_pos ? eff_pos : flux_pos;
17229 end = (eff_pos + eff_count) < (flux_pos + flux_count) ?
17230 (eff_pos + eff_count) : (flux_pos + flux_count);
17231 eff_pos = start;
17232 eff_count = end - start;
17233
17234 if (eff_count < 1) {
17235 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
17236 "No overlap between catalog and spectrum");
17237 cleanup;
17238 return NULL;
17239 }
17240
17241
17242
17243
17244
17245
17246 image = cpl_image_extract(efficiency, eff_pos + 1, 1,
17247 eff_pos + eff_count, 1);
17248
17249 smo_image = polysmooth(image, order, 50);
17250 cpl_image_delete(image);
17251
17252 smo_efficiency = cpl_image_duplicate(efficiency);
17253 smo_eff_data = cpl_image_get_data_float(smo_efficiency);
17254 cpl_image_copy(smo_efficiency, smo_image, eff_pos + 1, 1);
17255
17256 cpl_image_delete(smo_image);
17257
17258
17259
17260
17261
17262
17263
17264
17265
17266
17267 response = cpl_image_duplicate(spectrum);
17268 res_data = cpl_image_get_data_float(response);
17269
17270 for (i = 0; i < nx; i++) {
17271 if (eff_data[i] > 0.01 && flux_data[i] > 0.0)
17272 res_data[i] = data[i] / flux_data[i];
17273 else
17274 res_data[i] = 0.0;
17275 }
17276
17277
17278
17279
17280
17281
17282 image = cpl_image_extract(response, eff_pos + 1, 1, eff_pos + eff_count, 1);
17283
17284 smo_image = polysmooth(image, order, 50);
17285 cpl_image_delete(image);
17286
17287 smo_response = cpl_image_duplicate(response);
17288 smo_res_data = cpl_image_get_data_float(smo_response);
17289 cpl_image_copy(smo_response, smo_image, eff_pos + 1, 1);
17290
17291 cpl_image_delete(smo_image);
17292
17293 for (i = 0; i < nx; i++) {
17294 if (eff_data[i] > 0.01) {
17295 res_data[i] = 1 / res_data[i];
17296 smo_res_data[i] = 1 / smo_res_data[i];
17297 }
17298 else {
17299 res_data[i] = 0.0;
17300 smo_res_data[i] = 0.0;
17301 }
17302 }
17303
17304
17305
17306
17307
17308
17309 table = cpl_table_new(nx);
17310
17311 cpl_table_new_column(table, "WAVE", CPL_TYPE_FLOAT);
17312 cpl_table_set_column_unit(table, "WAVE", "Angstrom");
17313
17314 for (i = 0; i < nx; i++)
17315 cpl_table_set_float(table, "WAVE", i, startwave + dispersion*(i+0.5));
17316
17317 cpl_table_new_column(table, "STD_FLUX", CPL_TYPE_FLOAT);
17318 cpl_table_set_column_unit(table, "STD_FLUX",
17319 "10^(-16) erg/(cm^2 s Angstrom)");
17320 cpl_table_copy_data_float(table, "STD_FLUX", flux_data);
17321 cpl_image_delete(flux); flux = NULL;
17322
17323 cpl_table_new_column(table, "OBS_FLUX", CPL_TYPE_FLOAT);
17324 cpl_table_set_column_unit(table, "OBS_FLUX", "electron/(s Angstrom)");
17325 cpl_table_copy_data_float(table, "OBS_FLUX", data);
17326 cpl_image_delete(spectrum); spectrum = NULL;
17327
17328 cpl_table_new_column(table, "RAW_EFFICIENCY", CPL_TYPE_FLOAT);
17329 cpl_table_set_column_unit(table, "RAW_EFFICIENCY", "electron/photon");
17330 cpl_table_copy_data_float(table, "RAW_EFFICIENCY", eff_data);
17331 cpl_image_delete(efficiency); efficiency = NULL;
17332
17333 cpl_table_new_column(table, "EFFICIENCY", CPL_TYPE_FLOAT);
17334 cpl_table_set_column_unit(table, "EFFICIENCY", "electron/photon");
17335 cpl_table_copy_data_float(table, "EFFICIENCY", smo_eff_data);
17336 cpl_image_delete(smo_efficiency); smo_efficiency = NULL;
17337
17338 cpl_table_new_column(table, "RAW_RESPONSE", CPL_TYPE_FLOAT);
17339 cpl_table_set_column_unit(table, "RAW_RESPONSE",
17340 "10^(-16) erg/(cm^2 electron)");
17341 cpl_table_copy_data_float(table, "RAW_RESPONSE", res_data);
17342 cpl_image_delete(response); response = NULL;
17343
17344 cpl_table_new_column(table, "RESPONSE", CPL_TYPE_FLOAT);
17345 cpl_table_set_column_unit(table,
17346 "RESPONSE", "10^(-16) erg/(cm^2 electron)");
17347 cpl_table_copy_data_float(table, "RESPONSE", smo_res_data);
17348 cpl_image_delete(smo_response); smo_response = NULL;
17349
17350 cleanup;
17351
17352 return table;
17353 }
17354
17355 static double ksigma_vector(cpl_vector *values,
17356 double klow, double khigh, int kiter, int *good)
17357 {
17358 cpl_vector *accepted;
17359 double mean = 0.0;
17360 double sigma = 0.0;
17361 double *data = cpl_vector_get_data(values);
17362 int n = cpl_vector_get_size(values);
17363 int ngood = n;
17364 int count = 0;
17365 int i;
17366
17367
17368
17369
17370
17371
17372
17373 mean = cpl_vector_get_median(values);
17374
17375 for (i = 0; i < n; i++)
17376 sigma += (mean - data[i]) * (mean - data[i]);
17377
17378 sigma = sqrt(sigma / (n - 1));
17379
17380 while (kiter) {
17381 count = 0;
17382 for (i = 0; i < ngood; i++) {
17383 if (data[i]-mean < khigh*sigma && mean-data[i] < klow*sigma) {
17384 data[count] = data[i];
17385 ++count;
17386 }
17387 }
17388
17389 if (count == 0)
17390 break;
17391
17392
17393
17394
17395
17396
17397
17398 accepted = cpl_vector_wrap(count, data);
17399 mean = cpl_vector_get_mean(accepted);
17400 if (count > 1)
17401 sigma = cpl_vector_get_stdev(accepted);
17402 cpl_vector_unwrap(accepted);
17403
17404 if (count == ngood || count == 1)
17405 break;
17406
17407 ngood = count;
17408 --kiter;
17409 }
17410
17411 if (good)
17412 *good = ngood;
17413
17414 return mean;
17415 }
17416
17417
17436 cpl_image *mos_ksigma_stack(cpl_imagelist *imlist,
17437 double klow, double khigh, int kiter,
17438 cpl_image **good)
17439 {
17440 int ni, nx, ny, npix;
17441 cpl_image *out_ima;
17442 float *pout_ima;
17443 float *good_ima;
17444 cpl_image *image;
17445 float **data;
17446 cpl_vector *time_line;
17447 double *ptime_line;
17448 int ngood;
17449 int i, j;
17450
17451
17452 ni = cpl_imagelist_get_size(imlist);
17453
17454 image = cpl_imagelist_get(imlist, 0);
17455 nx = cpl_image_get_size_x(image);
17456 ny = cpl_image_get_size_y(image);
17457 npix = nx * ny;
17458
17459 out_ima = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
17460 pout_ima = cpl_image_get_data_float(out_ima);
17461
17462 if (good) {
17463 *good = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
17464 good_ima = cpl_image_get_data_float(*good);
17465 }
17466
17467 time_line = cpl_vector_new(ni);
17468 ptime_line = cpl_vector_get_data(time_line);
17469
17470 data = cpl_calloc(sizeof(float *), ni);
17471
17472 for (i = 0; i < ni; i++) {
17473 image = cpl_imagelist_get(imlist, i);
17474 data[i] = cpl_image_get_data_float(image);
17475 }
17476
17477 for (i = 0; i < npix; i++) {
17478 for (j = 0; j < ni; j++) {
17479 ptime_line[j] = data[j][i];
17480 }
17481 pout_ima[i] = ksigma_vector(time_line, klow, khigh, kiter, &ngood);
17482 if (good) {
17483 good_ima[i] = ngood;
17484 }
17485 }
17486
17487 cpl_free(data);
17488 cpl_vector_delete(time_line);
17489
17490 return out_ima;
17491
17492 }
17493
17494
17511 cpl_image *mos_apply_photometry(cpl_image *spectra, cpl_table *response,
17512 cpl_table *ext_table, double startwave,
17513 double dispersion, double gain,
17514 double exptime, double airmass)
17515 {
17516 cpl_image *extinction;
17517 cpl_image *outspectra;
17518 cpl_image *mapresponse;
17519 float *res_data;
17520 float *out_data;
17521 float *ext_data;
17522 int tlength, xlength, ylength;
17523 int i, j, k;
17524
17525
17526 if (spectra == NULL || ext_table == NULL || response == NULL) {
17527 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
17528 return NULL;
17529 }
17530
17531 res_data = cpl_table_get_data_float(response, "RESPONSE");
17532
17533 if (res_data == NULL) {
17534 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
17535 return NULL;
17536 }
17537
17538 tlength = cpl_table_get_nrow(response);
17539 xlength = cpl_image_get_size_x(spectra);
17540 ylength = cpl_image_get_size_y(spectra);
17541
17542 if (xlength != tlength) {
17543 mapresponse = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
17544 map_table(mapresponse, startwave + dispersion/2, dispersion,
17545 response, "WAVE", "RESPONSE");
17546 res_data = cpl_image_get_data_float(mapresponse);
17547 }
17548
17549
17550
17551
17552
17553
17554 extinction = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
17555 map_table(extinction, startwave + dispersion/2, dispersion,
17556 ext_table, "WAVE", "EXTINCTION");
17557
17558
17559
17560
17561
17562
17563 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
17564 cpl_image_exponential(extinction, 10.);
17565
17566 outspectra = cpl_image_duplicate(spectra);
17567
17568 ext_data = cpl_image_get_data_float(extinction);
17569 out_data = cpl_image_get_data_float(outspectra);
17570
17571 for (k = 0, i = 0; i < ylength; i++) {
17572 for (j = 0; j < xlength; j++, k++) {
17573 out_data[k] *= ext_data[j] * res_data[j];
17574 }
17575 }
17576
17577 cpl_image_delete(extinction);
17578 if (xlength != tlength) {
17579 cpl_image_delete(mapresponse);
17580 }
17581
17582 cpl_image_multiply_scalar(outspectra, gain / exptime / dispersion);
17583
17584 return outspectra;
17585 }
17586
17587
17604 cpl_image *mos_propagate_photometry_error(cpl_image *spectra,
17605 cpl_image *errors,
17606 cpl_table *response,
17607 cpl_table *ext_table,
17608 double startwave,
17609 double dispersion, double gain,
17610 double exptime, double airmass)
17611 {
17612 cpl_image *extinction;
17613 cpl_image *outerrors;
17614 cpl_image *mapresponse;
17615 cpl_image *maperror;
17616 float *err_data;
17617 float *out_data;
17618 float *ext_data;
17619 float *res_data;
17620 float *spe_data;
17621 int tlength, xlength, ylength;
17622 int i, j, k;
17623
17624
17625 if (errors == NULL || ext_table == NULL || response == NULL) {
17626 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
17627 return NULL;
17628 }
17629
17630 if (!cpl_table_has_column(response, "ERROR")) {
17631 return mos_apply_photometry(errors, response, ext_table, startwave,
17632 dispersion, gain, exptime, airmass);
17633 }
17634
17635 res_data = cpl_table_get_data_float(response, "RESPONSE");
17636
17637 if (res_data == NULL) {
17638 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
17639 return NULL;
17640 }
17641
17642 err_data = cpl_table_get_data_float(response, "ERROR");
17643
17644 if (err_data == NULL) {
17645 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
17646 return NULL;
17647 }
17648
17649 tlength = cpl_table_get_nrow(response);
17650 xlength = cpl_image_get_size_x(errors);
17651 ylength = cpl_image_get_size_y(errors);
17652
17653 if (xlength != tlength) {
17654 mapresponse = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
17655 map_table(mapresponse, startwave + dispersion/2, dispersion,
17656 response, "WAVE", "RESPONSE");
17657 res_data = cpl_image_get_data_float(mapresponse);
17658
17659 maperror = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
17660 map_table(maperror, startwave + dispersion/2, dispersion,
17661 response, "WAVE", "ERROR");
17662 err_data = cpl_image_get_data_float(maperror);
17663 }
17664
17665
17666
17667
17668
17669
17670 extinction = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
17671 map_table(extinction, startwave + dispersion/2, dispersion,
17672 ext_table, "WAVE", "EXTINCTION");
17673
17674
17675
17676
17677
17678
17679 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
17680 cpl_image_exponential(extinction, 10.);
17681
17682 outerrors = cpl_image_duplicate(errors);
17683
17684 ext_data = cpl_image_get_data_float(extinction);
17685 out_data = cpl_image_get_data_float(outerrors);
17686 spe_data = cpl_image_get_data_float(spectra);
17687
17688 for (k = 0, i = 0; i < ylength; i++) {
17689 for (j = 0; j < xlength; j++, k++) {
17690 out_data[k] = ext_data[j] *
17691 sqrt(err_data[j] * err_data[j] * spe_data[k] * spe_data[k] +
17692 res_data[j] * res_data[j] * out_data[k] * out_data[k]);
17693 }
17694 }
17695
17696 cpl_image_delete(extinction);
17697 if (xlength != tlength) {
17698 cpl_image_delete(maperror);
17699 }
17700
17701 cpl_image_multiply_scalar(outerrors, gain / exptime / dispersion);
17702
17703 return outerrors;
17704 }
17705
17706
17782 int mos_check_polarisation(cpl_image *q_image, cpl_image *q_error,
17783 cpl_image *u_image, cpl_image *u_error,
17784 double startwave, double dispersion,
17785 double band, cpl_table *pol_sta,
17786 double ra, double dec, char *filter,
17787 int *polarisation,
17788 double *p_offset, double *p_error,
17789 double *a_offset, double *a_error)
17790 {
17791 cpl_table *standard;
17792 cpl_image *q_noise;
17793 cpl_image *q_signal;
17794 cpl_image *u_noise;
17795 cpl_image *u_signal;
17796 cpl_image *noise;
17797 double *q_ndata;
17798 double *q_sdata;
17799 double *u_ndata;
17800 double *u_sdata;
17801 double arctol = 0.5;
17802 double mindist;
17803 double cwave;
17804 double bwave[] = {3650., 4450., 5510., 6580., 8060};
17805 char *bands = "UBVRI";
17806 char p_label[] = {' ', 'p', '\0'};
17807 char dp_label[] = {' ', 'd', 'p', '\0'};
17808 char a_label[] = {' ', 'a', '\0'};
17809 char da_label[] = {' ', 'd', 'a', '\0'};
17810 int nbands = strlen(bands);
17811 int selected;
17812 int first, last, count, center;
17813 int nx, col, row;
17814 int i, found, closest;
17815 int pband;
17816 int polarised;
17817 double q_obs;
17818 double q_err;
17819 double u_obs;
17820 double u_err;
17821 double p_obs;
17822 double p_err;
17823 double p_ref;
17824 double dp_ref;
17825 double a_obs;
17826 double a_err;
17827 double a_ref;
17828 double da_ref;
17829
17830
17831 *filter = '\0';
17832 *polarisation = 0;
17833 *p_offset = 0.0;
17834 *p_error = 0.0;
17835 *a_offset = 0.0;
17836 *a_error = 0.0;
17837
17838
17839
17840
17841
17842 cpl_table_select_all(pol_sta);
17843 cpl_table_and_selected_double(pol_sta, "RA", CPL_GREATER_THAN, ra-arctol);
17844 cpl_table_and_selected_double(pol_sta, "RA", CPL_LESS_THAN, ra+arctol);
17845 cpl_table_and_selected_double(pol_sta, "DEC", CPL_GREATER_THAN, dec-arctol);
17846 selected =
17847 cpl_table_and_selected_double(pol_sta, "DEC", CPL_LESS_THAN, dec+arctol);
17848
17849 if (selected == 0) {
17850 cpl_msg_warning(cpl_func, "No standard star found in FOV");
17851 return 1;
17852 }
17853
17854 if (selected > 1) {
17855 cpl_msg_warning(cpl_func,
17856 "Ambiguity: %d standard stars found in FOV", selected);
17857 return 1;
17858 }
17859
17860 standard = cpl_table_extract_selected(pol_sta);
17861
17862 cpl_msg_info(cpl_func, "Standard star: %s",
17863 cpl_table_get_string(standard, "name", 0));
17864
17865
17866
17867
17868
17869 polarised = cpl_table_get_int(standard, "polarised", 0, NULL);
17870
17871 cpl_msg_info(cpl_func, "This star is%sexpected to be polarised",
17872 polarised ? " " : " not ");
17873
17874
17875
17876
17877
17878
17879
17880
17881
17882 nx = cpl_image_get_size_x(q_error);
17883
17884 noise = cpl_image_collapse_median_create(q_error, 1, 0, 0);
17885 cpl_image_get_minpos(noise, &col, &row);
17886
17887 cpl_image_delete(noise);
17888
17889 if (col != 1) {
17890 cpl_table_delete(standard);
17891 cpl_msg_error(cpl_func,
17892 "Assertion failure!!! col = %d (it should be 1)", col);
17893 return 1;
17894 }
17895
17896 q_signal = cpl_image_extract(q_image, 1, row, nx, row);
17897 q_noise = cpl_image_extract(q_error, 1, row, nx, row);
17898 u_signal = cpl_image_extract(u_image, 1, row, nx, row);
17899 u_noise = cpl_image_extract(u_error, 1, row, nx, row);
17900
17901 q_sdata = cpl_image_get_data_double(q_signal);
17902 q_ndata = cpl_image_get_data_double(q_noise);
17903 u_sdata = cpl_image_get_data_double(u_signal);
17904 u_ndata = cpl_image_get_data_double(u_noise);
17905
17906
17907
17908
17909
17910
17911 first = -1;
17912 last = nx = cpl_image_get_size_x(q_signal);
17913 for (i = 0; i < nx; i++) {
17914 if (first < 0) {
17915 if (q_ndata[i] > 0.0) {
17916 first = i;
17917 }
17918 }
17919 else {
17920 if (q_ndata[i] <= 0.0) {
17921 last = i - 1;
17922 break;
17923 }
17924 }
17925 }
17926
17927 count = last - first + 1;
17928
17929 if (first < 0 || count < band) {
17930 cpl_table_delete(standard);
17931 cpl_image_delete(q_signal);
17932 cpl_image_delete(q_noise);
17933 cpl_image_delete(u_signal);
17934 cpl_image_delete(u_noise);
17935 cpl_msg_warning(cpl_func, "Too short spectrum (%d pixels)", count);
17936 return 1;
17937 }
17938
17939 center = (first + last) / 2;
17940 cwave = startwave + dispersion * center;
17941
17942
17943
17944
17945
17946
17947 found = 0;
17948 for (i = 0; i < nbands; i++) {
17949 p_label[0] = bands[i];
17950 if (cpl_table_is_valid(standard, p_label, 0)) {
17951 if (found == 0) {
17952 found = 1;
17953 mindist = fabs(bwave[i] - cwave);
17954 closest = i;
17955 }
17956 else if (mindist > fabs(bwave[i] - cwave)) {
17957 mindist = fabs(bwave[i] - cwave);
17958 closest = i;
17959 }
17960 }
17961 }
17962
17963 if (!found) {
17964 cpl_table_delete(standard);
17965 cpl_image_delete(q_signal);
17966 cpl_image_delete(q_noise);
17967 cpl_image_delete(u_signal);
17968 cpl_image_delete(u_noise);
17969 cpl_msg_warning(cpl_func, "No reference value available");
17970 return 1;
17971 }
17972
17973 center = (bwave[closest] - startwave) / dispersion;
17974 cwave = bwave[closest];
17975
17976
17977
17978
17979
17980
17981
17982 pband = floor(band / dispersion);
17983
17984 if (center - pband/2 < first || center + pband/2 > last) {
17985 cpl_table_delete(standard);
17986 cpl_image_delete(q_signal);
17987 cpl_image_delete(q_noise);
17988 cpl_image_delete(u_signal);
17989 cpl_image_delete(u_noise);
17990 cpl_msg_warning(cpl_func, "No reference value available");
17991 return 1;
17992 }
17993
17994 first = center - pband/2;
17995 last = center + pband/2;
17996
17997
17998
17999
18000
18001
18002 p_label[0] = bands[closest];
18003 dp_label[0] = bands[closest];
18004 a_label[0] = bands[closest];
18005 da_label[0] = bands[closest];
18006
18007 p_ref = cpl_table_get(standard, p_label, 0, NULL);
18008 dp_ref = cpl_table_get(standard, dp_label, 0, NULL);
18009 a_ref = cpl_table_get(standard, a_label, 0, NULL);
18010 da_ref = cpl_table_get(standard, da_label, 0, NULL);
18011
18012 cpl_msg_info(cpl_func,
18013 "The expected polarisation is %.2f +- %.2f %%",
18014 p_ref, dp_ref);
18015
18016 if (polarised) {
18017 cpl_msg_info(cpl_func,
18018 "The expected polarisation angle is %.2f +- %.2f degrees",
18019 a_ref, da_ref);
18020 }
18021
18022
18023
18024
18025
18026 q_obs = cpl_image_get_median_window(q_image, first, 1, last, 1);
18027 q_err = cpl_image_get_median_window(q_error, first, 1, last, 1);
18028 u_obs = cpl_image_get_median_window(u_image, first, 1, last, 1);
18029 u_err = cpl_image_get_median_window(u_error, first, 1, last, 1);
18030
18031
18032
18033
18034
18035 p_obs = sqrt(q_obs * q_obs + u_obs * u_obs);
18036 p_err = CPL_MATH_SQRT1_2 * 0.5 * (q_err + u_err);
18037
18038
18039
18040
18041
18042 a_obs = 0.0;
18043 if (polarised) {
18044 if (fabs(q_obs) < 0.00001) {
18045 if (u_obs > 0.0) {
18046 a_obs = 45.0;
18047 }
18048 else {
18049 a_obs = 135.0;
18050 }
18051 }
18052 else {
18053 a_obs = 0.5 * atan(u_obs / q_obs) * 180 / CPL_MATH_PI;
18054 if (q_obs > 0.0) {
18055 if (u_obs < 0.0) {
18056 a_obs += 180.;
18057 }
18058 }
18059 else {
18060 a_obs += 90.;
18061 }
18062 }
18063 }
18064
18065
18066
18067
18068
18069 a_err = 0.0;
18070 if (polarised) {
18071 a_err = sqrt(q_obs*q_obs*u_err*u_err + u_obs*u_obs*q_err*q_err)
18072 / (p_obs * p_obs)
18073 * 90 / CPL_MATH_PI;
18074 }
18075
18076 p_obs *= 100;
18077 p_err *= 100;
18078 cpl_msg_info(cpl_func,
18079 "The measured polarisation is %.2f +- %.2f %%",
18080 p_obs, p_err);
18081
18082 if (polarised) {
18083 cpl_msg_info(cpl_func,
18084 "The measured polarisation angle is %.2f +- %.2f degrees",
18085 a_obs, a_err);
18086 }
18087
18088 *filter = bands[closest];
18089 *polarisation = polarised;
18090
18091 if (polarised) {
18092 *p_offset = (p_obs - p_ref) / p_ref;
18093 *p_error = sqrt(p_err * p_err + dp_ref * dp_ref) / p_ref;
18094 }
18095 else {
18096 *p_offset = p_obs - p_ref;
18097 *p_error = sqrt(p_err * p_err + dp_ref * dp_ref);
18098 }
18099
18100 *a_offset = a_obs - a_ref;
18101 *a_error = sqrt(a_err*a_err + da_ref*da_ref);
18102
18103 return 0;
18104
18105 }
18106
18107
18139 int mos_compute_offset(cpl_table *reference, cpl_table *objects, double *offset)
18140 {
18141 cpl_array *offsets;
18142 int noffset;
18143 int nslits = cpl_table_get_nrow(reference);
18144 int *nref;
18145 int *nobj;
18146 int corr, maxcorr;
18147 int shift, best_shift;
18148 int i, j, k;
18149
18150 cpl_error_code status = CPL_ERROR_NONE;
18151
18152
18153 *offset = 0.0;
18154
18155 if (nslits != cpl_table_get_nrow(objects))
18156 return CPL_ERROR_INCOMPATIBLE_INPUT;
18157
18158 nref = fors_get_nobjs_perslit(reference);
18159 nobj = fors_get_nobjs_perslit(objects);
18160
18161 noffset = 0;
18162 for (i = 0; i < nslits; i++)
18163 noffset += nobj[i];
18164
18165 if (noffset == 0) {
18166 cpl_free(nref);
18167 cpl_free(nobj);
18168 return CPL_ERROR_DATA_NOT_FOUND;
18169 }
18170
18171 noffset = 0;
18172 for (i = 0; i < nslits; i++)
18173 noffset += nref[i];
18174
18175 if (noffset == 0) {
18176 cpl_free(nref);
18177 cpl_free(nobj);
18178 return CPL_ERROR_DATA_NOT_FOUND;
18179 }
18180
18181 offsets = cpl_array_new(noffset, CPL_TYPE_DOUBLE);
18182
18183 noffset = 0;
18184
18185 for (i = 0; i < nslits; i++) {
18186 if (nref[i] > 0 && nobj[i] > 0) {
18187 double shift;
18188 int length = cpl_table_get_int(objects, "length", i, NULL);
18189 double ytop = cpl_table_get_double(objects, "xtop", i, NULL);
18190 double ybottom = cpl_table_get_double(objects, "xbottom", i, NULL);
18191 int *aref = cpl_calloc(length, sizeof(int));
18192 int *aobj = cpl_calloc(length, sizeof(int));
18193 float *pref = cpl_calloc(nref[i], sizeof(float));
18194 float *pobj = cpl_calloc(nobj[i], sizeof(float));
18195
18196 for (j = 0; j < nref[i]; j++) {
18197 pref[j] = fors_get_object_position(reference, i, j + 1);
18198 aref[(int)pref[j]] = 1;
18199 }
18200
18201 for (j = 0; j < nobj[i]; j++) {
18202 pobj[j] = fors_get_object_position(objects, i, j + 1);
18203 aobj[(int)pobj[j]] = 1;
18204 }
18205
18206
18207
18208
18209
18210 aref[0] = 0;
18211 aref[length - 1] = 0;
18212 aobj[0] = 0;
18213 aobj[length - 1] = 0;
18214
18215
18216
18217
18218
18219
18220
18221
18222
18223
18224
18225
18226
18227
18228
18229
18230
18231
18232 maxcorr = 0;
18233 best_shift = length;
18234
18235 for (shift = length/2, j = 0; j <= length; shift--, j++) {
18236 int rstart, ostart, count;
18237
18238 if (shift > 0) {
18239 rstart = shift;
18240 ostart = 0;
18241 count = length - shift;
18242 }
18243 else {
18244 rstart = 0;
18245 ostart = -shift;
18246 count = length + shift;
18247 }
18248
18249 corr = 0;
18250 for (k = 0; k < count; k++) {
18251 corr += aref[rstart + k] * aobj[ostart + k];
18252 }
18253
18254 if (maxcorr < corr) {
18255 maxcorr = corr;
18256 best_shift = shift;
18257 }
18258 }
18259
18260 if (best_shift == length) {
18261
18262 cpl_free(aref);
18263 cpl_free(aobj);
18264 cpl_free(pref);
18265 cpl_free(pobj);
18266 continue;
18267 }
18268
18269
18270 for (j = 0; j < nref[i]; j++) {
18271 for (k = 0; k < nobj[i]; k++) {
18272 if (fabs(pref[j] - pobj[k] - best_shift) < 2) {
18273 double ccd_offset = (pref[j] - pobj[k])
18274 * (ytop - ybottom)
18275 / length;
18276
18277
18278
18279
18280
18281
18282
18283 cpl_array_set(offsets, noffset, ccd_offset);
18284 noffset++;
18285 break;
18286 }
18287 }
18288 }
18289
18290 cpl_free(aref);
18291 cpl_free(aobj);
18292 cpl_free(pref);
18293 cpl_free(pobj);
18294 }
18295
18296
18297 }
18298
18299 cpl_free(nref);
18300 cpl_free(nobj);
18301
18302
18303 if (noffset > 0) {
18304 if (noffset % 2) {
18305 *offset = cpl_array_get_median(offsets);
18306 }
18307 else {
18308 double *a = cpl_malloc(sizeof(double) * noffset);
18309 for (i = 0; i < noffset; i++) {
18310 a[i] = cpl_array_get_double(offsets, i, NULL);
18311 }
18312 *offset = (fors_tools_get_kth_double(a, noffset, (noffset-1)/2) +
18313 fors_tools_get_kth_double(a, noffset, (noffset/2))) / 2.0;
18314 cpl_free(a);
18315 }
18316 }
18317 else
18318 status = CPL_ERROR_DATA_NOT_FOUND;
18319
18320
18321 cpl_array_delete(offsets);
18322
18323 return status;
18324
18325 }
18326
18327
18339 cpl_error_code mos_image_shift(cpl_image *image, double dx, double dy)
18340 {
18341 cpl_image *source;
18342 int nx = cpl_image_get_size_x(image);
18343 int ny = cpl_image_get_size_y(image);
18344 float *idata;
18345 float *sdata;
18346 int i, j, pos;
18347 double xpos, ypos, xfrac, yfrac;
18348 int xint, yint;
18349
18350
18351 if (fabs(dx) >= nx || fabs(dy) >= ny)
18352 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
18353
18354 source = cpl_image_duplicate(image);
18355 idata = cpl_image_get_data_float(image);
18356 sdata = cpl_image_get_data_float(source);
18357
18358
18359
18360
18361
18362 yfrac = - dy - floor(- dy);
18363 xfrac = - dx - floor(- dx);
18364
18365 for (pos = 0, j = 0; j < ny; j++) {
18366 ypos = j - dy;
18367 yint = floor(ypos);
18368 for (i = 0; i < nx; i++) {
18369 xpos = i - dx;
18370 xint = floor(xpos);
18371 if (xint < 0 || yint < 0 || xint > nx - 2 || yint > ny - 2) {
18372 idata[pos] = 0.0;
18373 }
18374 else {
18375 idata[pos] = sdata[xint + nx*yint] * (1 - xfrac) * (1 - yfrac)
18376 + sdata[xint + 1 + nx*yint] * xfrac * (1 - yfrac)
18377 + sdata[xint + nx*(yint + 1)] * (1 - xfrac) * yfrac
18378 + sdata[xint + 1 + nx*(yint + 1)] * xfrac * yfrac;
18379 }
18380 pos++;
18381 }
18382 }
18383
18384 cpl_image_delete(source);
18385
18386 return CPL_ERROR_NONE;
18387 }
18388
18400 int mos_slit_closest_to_center(cpl_table *slits, int nx, int ny)
18401 {
18402 #ifdef CPL_SIZE_FORMAT
18403 cpl_size row;
18404 #else
18405 int row;
18406 #endif
18407
18408 cpl_table_duplicate_column(slits, "x", slits, "xtop");
18409 cpl_table_add_columns(slits, "x", "xbottom");
18410 cpl_table_divide_scalar(slits, "x", 2);
18411 cpl_table_subtract_scalar(slits, "x", nx/2);
18412 cpl_table_multiply_columns(slits, "x", "x");
18413
18414 cpl_table_duplicate_column(slits, "y", slits, "ytop");
18415 cpl_table_add_columns(slits, "y", "ybottom");
18416 cpl_table_divide_scalar(slits, "y", 2);
18417 cpl_table_subtract_scalar(slits, "y", ny/2);
18418 cpl_table_multiply_columns(slits, "y", "y");
18419
18420 cpl_table_add_columns(slits, "x", "y");
18421 cpl_table_get_column_minpos(slits, "x", &row);
18422
18423 cpl_table_erase_column(slits, "x");
18424 cpl_table_erase_column(slits, "y");
18425
18426 return row;
18427 }
18428
18448 cpl_error_code mos_extract_flux(cpl_image *image, cpl_table *slits,
18449 double xwidth, double ywidth,
18450 int dx, double gain, double *o_flux, double *o_err)
18451 {
18452 int nx = cpl_image_get_size_x(image);
18453 int ny = cpl_image_get_size_y(image);
18454 int slit = mos_slit_closest_to_center(slits, nx, ny);
18455 int ytop = (int)cpl_table_get(slits, "ytop", slit, NULL);
18456 int ybottom = (int)cpl_table_get(slits, "ybottom", slit, NULL);
18457 int dy = ytop - ybottom;
18458 int xcenter = (int)((cpl_table_get(slits, "xtop", slit, NULL) +
18459 cpl_table_get(slits, "xbottom", slit, NULL)) / 2);
18460 int xleft = xcenter - dx;
18461 int xright = xcenter + dx + 1;
18462 double area = xwidth * ywidth;
18463 int npix = (2*dx + 1) * dy;
18464 int count = 0;
18465 float *data = cpl_image_get_data_float(image);
18466 double flux = 0.0;
18467 double error = 0.0;
18468 int satur = 60000;
18469 int x, y;
18470
18471
18472 if (cpl_table_has_column(slits, "ywidth")) {
18473 area = cpl_table_get(slits, "xwidth", slit, NULL)
18474 * cpl_table_get(slits, "ywidth", slit, NULL);
18475 }
18476
18477 *o_flux = 0.0;
18478 *o_err = 0.0;
18479
18480 if (xleft < 0)
18481 xleft = 0;
18482
18483 if (xleft > nx)
18484 xleft = nx;
18485
18486 if (xright < 0)
18487 xright = 0;
18488
18489 if (xright > nx)
18490 xright = nx;
18491
18492 if (ytop < 0)
18493 ytop = 0;
18494
18495 if (ytop > ny)
18496 ytop = ny;
18497
18498 if (ybottom < 0)
18499 ybottom = 0;
18500
18501 if (ybottom > ny)
18502 ybottom = ny;
18503
18504 count = (xright - xleft) * (ytop - ybottom);
18505
18506 if (count == 0)
18507 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
18508
18509 count = 0;
18510
18511 for (y = ybottom; y < ytop; y++) {
18512 for (x = xleft; x < xright; x++) {
18513 double value = data[x + y * nx];
18514 if (value < satur) {
18515 flux += value;
18516 count++;
18517 }
18518 }
18519 }
18520
18521 if (count == 0)
18522 return CPL_ERROR_DIVISION_BY_ZERO;
18523
18524 error = sqrt(flux/gain);
18525
18526
18527
18528
18529
18530 flux *= (float)npix / count;
18531 error *= (float)npix / count;
18532
18533 flux /= area;
18534 error /= area;
18535
18536 *o_flux = flux;
18537 *o_err = error;
18538
18539 return CPL_ERROR_NONE;
18540 }
18541
18542
18565 cpl_error_code mos_extract_flux_mapped(cpl_image *image, cpl_table *slits,
18566 double xwidth, double ywidth,
18567 double lambda, double startwave,
18568 double dispersion, int dx, double gain,
18569 double *o_flux, double *o_err)
18570 {
18571 int nx = cpl_image_get_size_x(image);
18572 int ny = cpl_image_get_size_y(image);
18573 int slit = mos_slit_closest_to_center(slits, nx, ny);
18574 int dy = (int)cpl_table_get(slits, "length", slit, NULL);
18575 int ybottom = (int)cpl_table_get(slits, "position", slit, NULL);
18576 int ytop = ybottom + dy;
18577 int xcenter = (int)floor((lambda - startwave) / dispersion + 0.5);
18578 int xleft = xcenter - dx;
18579 int xright = xcenter + dx + 1;
18580 double area = xwidth * ywidth;
18581 int npix = (2*dx + 1) * dy;
18582 int count = 0;
18583 float *data = cpl_image_get_data_float(image);
18584 double flux = 0.0;
18585 double error = 0.0;
18586 int satur = 60000;
18587 int x, y;
18588
18589
18590 if (cpl_table_has_column(slits, "ywidth")) {
18591 area = cpl_table_get(slits, "xwidth", slit, NULL)
18592 * cpl_table_get(slits, "ywidth", slit, NULL);
18593 }
18594
18595 *o_flux = 0.0;
18596 *o_err = 0.0;
18597
18598 if (xleft < 0)
18599 xleft = 0;
18600
18601 if (xleft > nx)
18602 xleft = nx;
18603
18604 if (xright < 0)
18605 xright = 0;
18606
18607 if (xright > nx)
18608 xright = nx;
18609
18610 if (ytop < 0)
18611 ytop = 0;
18612
18613 if (ytop > ny)
18614 ytop = ny;
18615
18616 if (ybottom < 0)
18617 ybottom = 0;
18618
18619 if (ybottom > ny)
18620 ybottom = ny;
18621
18622 count = (xright - xleft) * (ytop - ybottom);
18623
18624 if (count == 0)
18625 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
18626
18627 count = 0;
18628
18629 for (y = ybottom; y < ytop; y++) {
18630 for (x = xleft; x < xright; x++) {
18631 double value = data[x + y * nx];
18632 if (value < satur) {
18633 flux += value;
18634 count++;
18635 }
18636 }
18637 }
18638
18639 if (count == 0)
18640 return CPL_ERROR_DIVISION_BY_ZERO;
18641
18642 error = sqrt(flux/gain);
18643
18644
18645
18646
18647
18648 flux *= (float)npix / count;
18649 error *= (float)npix / count;
18650
18651 flux /= area;
18652 error /= area;
18653
18654 *o_flux = flux;
18655 *o_err = error;
18656
18657 return CPL_ERROR_NONE;
18658
18659 }
18660
18661
18675 int mos_median_in_slit(cpl_table *table, cpl_table *slits, int slit,
18676 char *label, double *mvalue)
18677 {
18678 int position = cpl_table_get_int(slits, "position", slit, NULL);
18679 int length = cpl_table_get_int(slits, "length", slit, NULL);
18680 cpl_table *tmp = cpl_table_extract(table, position, length);
18681
18682 *mvalue = cpl_table_get_column_median(tmp, label);
18683 cpl_table_delete(tmp);
18684
18685 if (cpl_error_get_code() != CPL_ERROR_NONE)
18686 return 1;
18687
18688 return 0;
18689 }
18690
18691
18703 cpl_image *mos_image_filter_median(cpl_image *image, int nx, int ny)
18704 {
18705 cpl_mask *kernel = cpl_mask_new(nx, ny);
18706 cpl_image *filtered = cpl_image_new(cpl_image_get_size_x(image),
18707 cpl_image_get_size_y(image),
18708 cpl_image_get_type(image));
18709
18710 cpl_mask_not(kernel);
18711 cpl_image_filter_mask(filtered, image, kernel,
18712 CPL_FILTER_MEDIAN, CPL_BORDER_FILTER);
18713 cpl_mask_delete(kernel);
18714
18715 return filtered;
18716 }