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 static cpl_polynomial *read_global_distortion(cpl_table *global, cpl_size row);
00044
00045
00046
00047
00048
00049
00050
00051
00052 float cpl_tools_get_median_float(float *, cpl_size);
00053
00054 #define MAX_COLNAME (80)
00055 #define STRETCH_FACTOR (1.20)
00056
00057
00058
00059 static int mos_multiplex = -1;
00060 static int mos_region_size = 800;
00061
00062 static double default_lines_hi[] = {
00063 5577.338,
00064 5889.953,
00065 5895.923,
00066 5915.301,
00067 5932.862,
00068 5953.420,
00069 6257.961,
00070 6287.434,
00071 6300.304,
00072 6306.869,
00073 6363.780,
00074 6498.729,
00075 6533.044,
00076 6553.617,
00077 6841.945,
00078 6863.955,
00079 6870.994,
00080 6889.288,
00081 6900.833,
00082 6912.623,
00083 6923.220,
00084 6939.521,
00085 6969.930,
00086 7003.858,
00087 7244.907,
00088 7276.405,
00089 7284.439,
00090 7316.282,
00091 7329.148,
00092 7340.885,
00093 7358.659,
00094 7571.746,
00095 7750.640,
00096 7759.996,
00097 7794.112,
00098 7808.467,
00099 7821.503,
00100 7841.266,
00101 7913.708,
00102 7949.204,
00103 7964.650,
00104 7993.332,
00105 8014.059,
00106 8310.719,
00107 8344.602,
00108 8382.392,
00109 8399.170,
00110 8415.231,
00111 8430.174,
00112 8452.250,
00113 8493.389,
00114 8791.186,
00115 8827.096,
00116 8885.850,
00117 8903.114,
00118 8943.395,
00119 8988.366
00120 };
00121
00122 static double default_lines_lo[] = {
00123 5577.338,
00124 6300.304,
00125 6863.955,
00126 7571.746,
00127 7964.650,
00128 7993.332
00129 };
00130
00131
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
00197
00198
00199
00200
00201 static void mos_seed(void)
00202 {
00203 srand((unsigned int)time((time_t *)0));
00204 }
00205
00206 static double mos_randg(int seme)
00207 {
00208 static int doit = 1;
00209 static int gotit = 1;
00210 double x1, x2, w, y1;
00211 static double y2;
00212
00213 if (gotit && seme) {
00214 mos_seed();
00215 gotit = 0;
00216 }
00217
00218 if (doit) {
00219 doit = 0;
00220 do {
00221 x1 = 2.0 * (double)rand() / RAND_MAX - 1.0;
00222 x2 = 2.0 * (double)rand() / RAND_MAX - 1.0;
00223 w = x1 * x1 + x2 * x2;
00224 } while (w >= 1.0 || w == 0.0);
00225
00226 w = sqrt( (-2.0 * log(w)) / w);
00227
00228 y1 = x1 * w;
00229 y2 = x2 * w;
00230 return y1;
00231 }
00232
00233 doit = 1;
00234 return y2;
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 static cpl_image *mos_image_vertical_median_filter(cpl_image *ima_in,
00246 int filtsizey, int refrow,
00247 int above, int below, int step)
00248 {
00249
00250 const char *func = "mos_image_general_median_filter";
00251
00252 cpl_image *filt_img = NULL;
00253 int col, row;
00254 float *buf = NULL;
00255 float *data;
00256 float *fdata;
00257 int upright_y, loleft_y;
00258 int j;
00259 int yIsEven = !(filtsizey - (filtsizey/2)*2);
00260 int f2y;
00261 int nx = cpl_image_get_size_x(ima_in);
00262 int ny = cpl_image_get_size_y(ima_in);
00263 int firstRow;
00264
00265
00266 if (yIsEven) filtsizey++;
00267
00268 if (ny <= filtsizey) {
00269 cpl_msg_error(func,
00270 "Median filter size: %d, image size: %d", filtsizey, ny);
00271 return NULL;
00272 }
00273
00274 f2y = filtsizey / 2;
00275
00276 filt_img = cpl_image_duplicate(ima_in);
00277 buf = cpl_malloc(filtsizey * sizeof(float));
00278 data = cpl_image_get_data(ima_in);
00279 fdata = cpl_image_get_data(filt_img);
00280
00281 firstRow = refrow - step * (below / step);
00282 if (firstRow < f2y)
00283 firstRow += step;
00284
00285 for (col = 0; col < nx; col++) {
00286 for (row = firstRow; row < refrow + above; row += step) {
00287 if (row >= ny - f2y)
00288 break;
00289 loleft_y = row - f2y;
00290 upright_y = row + f2y + 1;
00291 for (j = loleft_y; j < upright_y; j++)
00292 buf[j - loleft_y] = data[col + j * nx];
00293
00294 fdata[col + row * nx] = cpl_tools_get_median_float(buf, filtsizey);
00295 }
00296 }
00297
00298 cpl_free(buf);
00299
00300 return filt_img;
00301
00302 }
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 static int peakPosition(const float *data, int size, float *position,
00322 int minPoints)
00323 {
00324 int i;
00325 int count = 0;
00326 float *copy;
00327 float max, median, level, pos, variance, uniformVariance;
00328 double sum, weights;
00329
00330
00331 if (data == NULL)
00332 return 1;
00333
00334 if (size < 5)
00335 return 1;
00336
00337
00338
00339
00340
00341
00342 copy = (float *) cpl_malloc(size*sizeof(float));
00343 for (i = 0; i < size; i++)
00344 copy[i] = data[i];
00345 median = cpl_tools_get_median_float(copy, size);
00346 cpl_free(copy);
00347
00348
00349
00350
00351
00352
00353 max = data[0];
00354 for (i = 1; i < size; i++)
00355 if (data[i] > max)
00356 max = data[i];
00357
00358
00359
00360
00361
00362
00363
00364 if (max-median < 0.00001)
00365 return 1;
00366
00367
00368
00369
00370
00371
00372
00373 level = (max + median) / 2;
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 count = 0;
00384 for (i = 0, sum = 0., weights = 0.; i < size; i++) {
00385 if (data[i] > level) {
00386 count++;
00387 weights += (data[i] - median);
00388 sum += i * (data[i] - median);
00389 }
00390 }
00391
00392
00393
00394
00395
00396
00397
00398 if (count < minPoints)
00399 return 1;
00400
00401 pos = sum / weights;
00402 for (i = 0, sum = 0., weights = 0.; i < size; i++) {
00403 if (data[i] > level) {
00404 weights++;
00405 sum += (i - pos) * (i - pos);
00406 }
00407 }
00408 variance = sqrt(sum / weights);
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418 uniformVariance = sqrt(size*size/3 - pos*size + pos*pos);
00419
00420 if (variance > 0.8 * uniformVariance)
00421 return 1;
00422
00423 *position = pos + 0.5;
00424
00425 return 0;
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
00471
00472
00473
00474
00475 static double values_to_dx(double v1, double v2, double v3)
00476 {
00477
00478 static double epsilon = 0.00000001;
00479 double r = 2.0;
00480
00481
00482 if (v1 > v2 || v3 > v2)
00483 return r;
00484
00485 if (2 * v2 - v1 - v3 < epsilon)
00486 return r;
00487
00488 r = 0.5 * (v3 - v1) / (2 * v2 - v3 - v1);
00489
00490 return r;
00491
00492 }
00493
00494
00495
00496
00497
00498
00499
00500 static float *min_filter(float *buffer, int length, int size)
00501 {
00502 float *minf = cpl_calloc(length, sizeof(float));
00503 float min;
00504 int start = size / 2;
00505 int end = length - size / 2;
00506 int i, j;
00507
00508
00509 for (i = start; i < end; i++) {
00510 min = buffer[i-start];
00511 for (j = i - start + 1; j <= i + start; j++)
00512 if (min > buffer[j])
00513 min = buffer[j];
00514 minf[i] = min;
00515 }
00516
00517 for (i = 0; i < start; i++)
00518 minf[i] = minf[start];
00519
00520 for (i = end; i < length; i++)
00521 minf[i] = minf[end-1];
00522
00523 return minf;
00524 }
00525
00526
00527
00528
00529
00530
00531
00532 static float *max_filter(float *buffer, int length, int size)
00533 {
00534 float *maxf = cpl_calloc(length, sizeof(float));
00535 float max;
00536 int start = size / 2;
00537 int end = length - size / 2;
00538 int i, j;
00539
00540
00541 for (i = start; i < end; i++) {
00542 max = buffer[i-start];
00543 for (j = i - start + 1; j <= i + start; j++)
00544 if (max < buffer[j])
00545 max = buffer[j];
00546 maxf[i] = max;
00547 }
00548
00549 for (i = 0; i < start; i++)
00550 maxf[i] = maxf[start];
00551
00552 for (i = end; i < length; i++)
00553 maxf[i] = maxf[end-1];
00554
00555 return maxf;
00556 }
00557
00558
00559
00560
00561
00562
00563
00564 static float *smo_filter(float *buffer, int length, int size)
00565 {
00566 float *smof = cpl_calloc(length, sizeof(float));
00567 double sum;
00568 int start = size / 2;
00569 int end = length - size / 2;
00570 int i, j;
00571
00572
00573 for (i = start; i < end; i++) {
00574 sum = 0.0;
00575 for (j = i - start; j <= i + start; j++)
00576 sum += buffer[j];
00577 smof[i] = sum / size;
00578 }
00579
00580 for (i = 0; i < start; i++)
00581 smof[i] = smof[start];
00582
00583 for (i = end; i < length; i++)
00584 smof[i] = smof[end-1];
00585
00586 return smof;
00587 }
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608 static cpl_polynomial *read_global_distortion(cpl_table *global, cpl_size row)
00609 {
00610 cpl_polynomial *poly = NULL;
00611 cpl_size p[2];
00612 cpl_size degree = 2;
00613 int null;
00614 double coeff;
00615
00616 char name[MAX_COLNAME];
00617
00618
00619 for (p[0] = 0; p[0] <= degree; p[0]++) {
00620 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
00621 snprintf(name, MAX_COLNAME, "a%"CPL_SIZE_FORMAT"%"CPL_SIZE_FORMAT"", p[0], p[1]);
00622 coeff = cpl_table_get_double(global, name, row, &null);
00623 if (null)
00624 continue;
00625 if (poly == NULL)
00626 poly = cpl_polynomial_new(2);
00627 cpl_polynomial_set_coeff(poly, p, coeff);
00628 }
00629 }
00630
00631 return poly;
00632 }
00633
00634 static cpl_table *write_global_distortion(cpl_table *global, int row,
00635 cpl_polynomial *poly)
00636 {
00637 cpl_table *table;
00638 cpl_size p[2];
00639 cpl_size degree = 2;
00640 int nrow = 13;
00641
00642 char name[MAX_COLNAME];
00643
00644
00645 if (global) {
00646 table = global;
00647 }
00648 else {
00649 table = cpl_table_new(nrow);
00650 for (p[0] = 0; p[0] <= degree; p[0]++) {
00651 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
00652 snprintf(name, MAX_COLNAME, "a%"CPL_SIZE_FORMAT"%"CPL_SIZE_FORMAT"", p[0], p[1]);
00653 cpl_table_new_column(table, name, CPL_TYPE_DOUBLE);
00654 }
00655 }
00656 }
00657
00658 if (poly) {
00659 for (p[0] = 0; p[0] <= degree; p[0]++) {
00660 for (p[1] = 0; p[1] <= degree - p[0]; p[1]++) {
00661 snprintf(name, MAX_COLNAME, "a%"CPL_SIZE_FORMAT"%"CPL_SIZE_FORMAT"", p[0], p[1]);
00662 cpl_table_set_double(table, name, row,
00663 cpl_polynomial_get_coeff(poly, p));
00664 }
00665 }
00666 }
00667
00668 return table;
00669 }
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681 #define SEGNO(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
00682 static int robustLinearFit(cpl_bivector *list, double *a, double *b,
00683 double *abdev)
00684 {
00685 cpl_vector *vx;
00686 cpl_vector *vy;
00687 cpl_vector *va;
00688
00689 double aa, bb, bcomp, b1, b2, del, abdevt, f, f1, f2, sigb, temp, d, sum;
00690 double sx, sy, sxy, sxx, chisq;
00691 double *arr;
00692 double aa_ls, bb_ls;
00693 double *x;
00694 double *y;
00695 int np;
00696 int iter;
00697 int max_iterate = 30;
00698 int i;
00699
00700
00701 np = cpl_bivector_get_size(list);
00702 vx = cpl_bivector_get_x(list);
00703 vy = cpl_bivector_get_y(list);
00704 x = cpl_vector_get_data(vx);
00705 y = cpl_vector_get_data(vy);
00706
00707 sx = sy = sxx = sxy = 0.00;
00708 for (i = 0; i < np; i++) {
00709 sx += x[i];
00710 sy += y[i];
00711 sxy += x[i] * y[i];
00712 sxx += x[i] * x[i];
00713 }
00714
00715 del = np * sxx - sx * sx;
00716 aa_ls = aa = (sxx * sy - sx * sxy) / del;
00717 bb_ls = bb = (np * sxy - sx * sy) / del;
00718
00719 chisq = 0.00;
00720 for (i = 0; i < np; i++) {
00721 temp = y[i] - (aa+bb*x[i]);
00722 temp *= temp;
00723 chisq += temp;
00724 }
00725
00726 va = cpl_vector_new(np);
00727 arr = cpl_vector_get_data(va);
00728 sigb = sqrt(chisq/del);
00729 b1 = bb;
00730
00731 bcomp = b1;
00732 sum = 0.00;
00733 for (i = 0; i < np; i++) {
00734 arr[i] = y[i] - bcomp * x[i];
00735 }
00736 aa = cpl_vector_get_median_const(va);
00737 abdevt = 0.0;
00738 for (i = 0; i < np; i++) {
00739 d = y[i] - (bcomp * x[i] + aa);
00740 abdevt += fabs(d);
00741 if (y[i] != 0.0)
00742 d /= fabs(y[i]);
00743 if (fabs(d) > 1e-7)
00744 sum += (d >= 0.0 ? x[i] : -x[i]);
00745 }
00746 f1 = sum;
00747
00748 b2 = bb + SEGNO(3.0 * sigb, f1);
00749
00750 bcomp = b2;
00751 sum = 0.00;
00752 for (i = 0; i < np; i++) {
00753 arr[i] = y[i] - bcomp * x[i];
00754 }
00755 aa = cpl_vector_get_median_const(va);
00756 abdevt = 0.0;
00757 for (i = 0; i < np; i++) {
00758 d = y[i] - (bcomp * x[i] + aa);
00759 abdevt += fabs(d);
00760 if (y[i] != 0.0)
00761 d /= fabs(y[i]);
00762 if (fabs(d) > 1e-7)
00763 sum += (d >= 0.0 ? x[i] : -x[i]);
00764 }
00765 f2 = sum;
00766
00767 if (fabs(b2-b1)<1e-7) {
00768 *a = aa;
00769 *b = bb;
00770 *abdev = abdevt / (double)np;
00771 cpl_vector_delete(va);
00772 return 0;
00773 }
00774
00775 iter = 0;
00776 while (f1*f2 > 0.0) {
00777 bb = 2.0*b2-b1;
00778 b1 = b2;
00779 f1 = f2;
00780 b2 = bb;
00781
00782 bcomp = b2;
00783 sum = 0.00;
00784 for (i = 0; i < np; i++) {
00785 arr[i] = y[i] - bcomp * x[i];
00786 }
00787 aa = cpl_vector_get_median_const(va);
00788 abdevt = 0.0;
00789 for (i = 0; i < np; i++) {
00790 d = y[i] - (bcomp * x[i] + aa);
00791 abdevt += fabs(d);
00792 if (y[i] != 0.0)
00793 d /= fabs(y[i]);
00794 if (fabs(d) > 1e-7)
00795 sum += (d >= 0.0 ? x[i] : -x[i]);
00796 }
00797 f2 = sum;
00798 iter++;
00799 if (iter >= max_iterate)
00800 break;
00801 }
00802 if (iter >= max_iterate) {
00803 *a = aa_ls;
00804 *b = bb_ls;
00805 *abdev = -1.0;
00806 cpl_vector_delete(va);
00807 return 1;
00808 }
00809
00810 sigb = 0.01 * sigb;
00811 while (fabs(b2-b1) > sigb) {
00812 bb = 0.5 * (b1 + b2);
00813 if ((fabs(bb-b1) < 1e-7) || (fabs(bb-b2) < 1e-7))
00814 break;
00815 bcomp = bb;
00816 sum = 0.0;
00817 for (i = 0; i < np; i++) {
00818 arr[i] = y[i] - bcomp * x[i];
00819 }
00820 aa = cpl_vector_get_median_const(va);
00821 abdevt = 0.0;
00822 for (i = 0; i < np; i++) {
00823 d = y[i] - (bcomp * x[i] + aa);
00824 abdevt += fabs(d);
00825 if (y[i] != 0.0)
00826 d /= fabs(y[i]);
00827 if (fabs(d) > 1e-7)
00828 sum += (d >= 0.0 ? x[i] : -x[i]);
00829 }
00830 f = sum;
00831
00832 if (f*f1 >= 0.0) {
00833 f1=f;
00834 b1=bb;
00835 }
00836 else {
00837 f2=f;
00838 b2=bb;
00839 }
00840 }
00841 cpl_vector_delete(va);
00842 *a = aa;
00843 *b = bb;
00844 *abdev = abdevt / np;
00845 return 0;
00846 }
00847 #undef SEGNO
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859 cpl_table *mos_hough_table(cpl_table *table, const char *x, const char *y)
00860 {
00861 cpl_table *output;
00862 double *xdata;
00863 double *ydata;
00864 double *xodata;
00865 double *yodata;
00866 int npoints;
00867 int opoints;
00868 int i, j, k;
00869
00870
00871 npoints = cpl_table_get_nrow(table);
00872 opoints = npoints*(npoints-1)/2;
00873
00874 output = cpl_table_new(opoints);
00875 cpl_table_new_column(output, "m", CPL_TYPE_DOUBLE);
00876 cpl_table_new_column(output, "q", CPL_TYPE_DOUBLE);
00877 cpl_table_fill_column_window_double(output, "m", 0, opoints, 0.0);
00878 cpl_table_fill_column_window_double(output, "q", 0, opoints, 0.0);
00879
00880 xodata = cpl_table_get_data_double(output, "m");
00881 yodata = cpl_table_get_data_double(output, "q");
00882
00883 cpl_table_cast_column(table, x, "x", CPL_TYPE_DOUBLE);
00884 cpl_table_cast_column(table, y, "y", CPL_TYPE_DOUBLE);
00885
00886 xdata = cpl_table_get_data_double(table, "x");
00887 ydata = cpl_table_get_data_double(table, "y");
00888
00889 k = 0;
00890 for (i = 0; i < npoints; i++) {
00891 for (j = i+1; j < npoints; j++) {
00892 xodata[k] = (ydata[i]-ydata[j])/(xdata[i]-xdata[j]);
00893 yodata[k] = ydata[i] - xodata[k] * xdata[i];
00894 k++;
00895 }
00896 }
00897
00898 if (k != opoints)
00899 printf("Assert k = %d, expected %d\n", k, opoints);
00900
00901 cpl_table_erase_column(table, "x");
00902 cpl_table_erase_column(table, "y");
00903
00904 return output;
00905 }
00906
00907
00908
00909
00910
00911
00912
00913 static void mos_extraction(cpl_image *sciwin, cpl_image *sci_var_win,
00914 cpl_image *skywin,
00915 cpl_image *extracted, cpl_image *sky,
00916 cpl_image *error, int nobjects, int extraction,
00917 double ron, double conad, int ncomb)
00918 {
00919
00920 cpl_vector *vprofile;
00921 cpl_image *smowin;
00922
00923 int i, j;
00924 int specLen;
00925 int numRows;
00926 int index;
00927 int iter;
00928 int maxIter = 2;
00929 int smoothBox = 31;
00930 double nsigma = 5.0;
00931
00932 double sumWeight, sum, sumSky, sumProf, sumVar, variance, weight;
00933 double *profile;
00934 double *buffer;
00935 float *edata;
00936 float *ekdata;
00937 float *endata;
00938 float *sdata;
00939 float *kdata;
00940 float *fdata;
00941 float *vardata;
00942
00943 double value;
00944
00945
00946 specLen = cpl_image_get_size_x(sciwin);
00947 numRows = cpl_image_get_size_y(sciwin);
00948
00949 edata = cpl_image_get_data(extracted);
00950 edata += nobjects * specLen;
00951
00952 ekdata = cpl_image_get_data(sky);
00953 ekdata += nobjects * specLen;
00954
00955 endata = cpl_image_get_data(error);
00956 endata += nobjects * specLen;
00957
00958 sdata = cpl_image_get_data(sciwin);
00959 kdata = cpl_image_get_data(skywin);
00960 if(sci_var_win != NULL)
00961 vardata = cpl_image_get_data(sci_var_win);
00962
00963
00964
00965
00966
00967
00968 if (extraction && numRows > 5) {
00969 smowin = mos_image_filter_median(sciwin, 3, 3);
00970 fdata = cpl_image_get_data(smowin);
00971 for (i = 0; i < specLen; i++)
00972 for (j = 0, edata[i] = 0.0; j < numRows; j++)
00973 edata[i] += fdata[i + j * specLen];
00974 cpl_image_delete(smowin);
00975 }
00976 else {
00977 for (i = 0; i < specLen; i++)
00978 for (j = 0, edata[i] = 0.0; j < numRows; j++)
00979 edata[i] += sdata[i + j * specLen];
00980 }
00981
00982 if (extraction) {
00983
00984 profile = cpl_calloc(specLen * numRows, sizeof(double));
00985 buffer = cpl_calloc(specLen, sizeof(double));
00986
00987 for (iter = 0; iter < maxIter; iter++) {
00988
00989
00990
00991
00992
00993 for (i = 0; i < specLen; i++) {
00994 for (j = 0; j < numRows; j++) {
00995 index = i + j * specLen;
00996
00997 if (fabs(edata[i]) > 0.00001)
00998 profile[index] = sdata[index] / edata[i];
00999 else
01000 profile[index] = 0.0;
01001 }
01002 }
01003
01004 for (j = 0; j < numRows; j++) {
01005
01006
01007
01008
01009
01010 for (i = 0; i < specLen - smoothBox; i++) {
01011 vprofile = cpl_vector_wrap(smoothBox, profile + i + j*specLen);
01012 value = cpl_vector_get_median_const(vprofile);
01013 cpl_vector_unwrap(vprofile);
01014 if (value < 0)
01015 value = 0.0;
01016 buffer[i + smoothBox / 2] = value;
01017 }
01018
01019
01020
01021
01022
01023 vprofile = cpl_vector_wrap(smoothBox / 2, profile + j*specLen);
01024 value = cpl_vector_get_mean(vprofile);
01025 cpl_vector_unwrap(vprofile);
01026
01027 if (value < 0)
01028 value = 0.0;
01029
01030 for (i = 0; i < smoothBox / 2; i++)
01031 buffer[i] = value;
01032
01033 vprofile = cpl_vector_wrap(smoothBox / 2,
01034 profile + specLen - smoothBox/2 + j*specLen);
01035 value = cpl_vector_get_mean(vprofile);
01036 cpl_vector_unwrap(vprofile);
01037
01038 if (value < 0)
01039 value = 0.0;
01040
01041 for (i = 0; i < smoothBox / 2; i++)
01042 buffer[i + specLen - smoothBox / 2] = value;
01043
01044 for (i = 0; i < specLen; i++)
01045 profile[i + j * specLen] = buffer[i];
01046
01047 }
01048
01049
01050
01051
01052
01053 for (i = 0; i < specLen; i++) {
01054 for (j = 0, value = 0.0; j < numRows; j++)
01055 value += profile[i + j * specLen];
01056 if (value > 0.00001)
01057 for (j = 0; j < numRows; j++)
01058 profile[i + j * specLen] /= value;
01059 else
01060 for (j = 0; j < numRows; j++)
01061 profile[i + j * specLen] = 0.0;
01062 }
01063
01064
01065
01066
01067
01068
01069 for (i = 0; i < specLen; i++) {
01070 sum = 0.0;
01071 sumSky = 0.0;
01072 sumWeight = 0.0;
01073 sumProf = 0.0;
01074 sumVar = 0;
01075 for (j = 0; j < numRows; j++) {
01076 index = i + j * specLen;
01077
01078
01079
01080
01081
01082
01083 variance = ron*ron + fabs(edata[i] * profile[index] + kdata[index])
01084 / conad;
01085 variance /= ncomb;
01086 value = sdata[index] - edata[i] * profile[index];
01087 if (fabs(value) / sqrt(variance) < nsigma) {
01088 weight = 1000000 * profile[index] / variance;
01089 sum += weight * sdata[index];
01090 sumSky += weight * kdata[index];
01091 sumWeight += weight * profile[index];
01092 sumProf += profile[index];
01093
01094
01095
01096 if(sci_var_win != NULL)
01097 sumVar += weight * weight * vardata[index];
01098 }
01099 }
01100
01101 if (sumWeight > 0.00001) {
01102 edata[i] = sum / sumWeight;
01103 ekdata[i] = sumSky / sumWeight;
01104 if(sci_var_win != NULL)
01105 endata[i] = sqrt(sumVar / sumWeight / sumWeight);
01106 else
01107 endata[i] = 1000 * sqrt(sumProf / sumWeight);
01108 }
01109 else {
01110
01111
01112
01113
01114
01115
01116 }
01117 }
01118 }
01119 cpl_free(profile);
01120 cpl_free(buffer);
01121 }
01122 else {
01123
01124
01125
01126
01127
01128
01129 for (i = 0; i < specLen; i++)
01130 for (j = 0, ekdata[i] = 0.0; j < numRows; j++)
01131 ekdata[i] += kdata[i + j * specLen];
01132
01133
01134
01135
01136 for (i = 0; i < specLen; i++)
01137 {
01138 if(sci_var_win != NULL)
01139 {
01140
01141 for (j = 0, endata[i] = 0.0; j < numRows; j++)
01142 endata[i] += vardata[i + j * specLen];
01143 endata[i] = sqrt(endata[i]);
01144 }
01145 else
01146 endata[i] = sqrt(ron*ron + fabs(edata[i] + ekdata[i]) / conad);
01147
01148 }
01149 }
01150
01151 }
01152
01153
01200 cpl_table *mos_global_distortion(cpl_table *slits, cpl_table *maskslits,
01201 cpl_table *ids, cpl_table *crv,
01202 double reference)
01203 {
01204 const char *func = "mos_global_distortion";
01205
01206 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01207
01208 cpl_table *global = NULL;
01209 cpl_table *coeff;
01210 cpl_table *dummy;
01211 cpl_vector *ci;
01212 cpl_vector *xmask;
01213 cpl_vector *ymask;
01214 cpl_bivector *mask;
01215 cpl_vector *xccd;
01216 cpl_vector *yccd;
01217 cpl_bivector *ccd;
01218 cpl_polynomial *poly;
01219 double *xtop;
01220 double *ytop;
01221 double *xbottom;
01222 double *ybottom;
01223 double *mxtop;
01224 double *mytop;
01225 double *mxbottom;
01226 double *mybottom;
01227 int *position;
01228 int *length;
01229 int *slit_id;
01230 int *mslit_id;
01231 int nslits, nmaskslits, npoints;
01232 int order;
01233 int i, j;
01234 int minslit = 6;
01235
01236
01237 if (slits == NULL || maskslits == NULL || ids == NULL || crv == NULL) {
01238 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01239 return NULL;
01240 }
01241
01242 nslits = cpl_table_get_nrow(slits);
01243
01244 if (nslits < minslit) {
01245 cpl_msg_warning(func, "Too few slits (%d < %d) for global "
01246 "distortion model determination", nslits, minslit);
01247 return NULL;
01248 }
01249
01250 nmaskslits = cpl_table_get_nrow(maskslits);
01251
01252 length = cpl_table_get_data_int(slits, "length");
01253 position = cpl_table_get_data_int(slits, "position");
01254 slit_id = cpl_table_get_data_int(slits, "slit_id");
01255 mslit_id = cpl_table_get_data_int(maskslits, "slit_id");
01256 xtop = cpl_table_get_data_double(slits, "xtop");
01257 ytop = cpl_table_get_data_double(slits, "ytop");
01258 xbottom = cpl_table_get_data_double(slits, "xbottom");
01259 ybottom = cpl_table_get_data_double(slits, "ybottom");
01260 mxtop = cpl_table_get_data_double(maskslits, "xtop");
01261 mytop = cpl_table_get_data_double(maskslits, "ytop");
01262 mxbottom = cpl_table_get_data_double(maskslits, "xbottom");
01263 mybottom = cpl_table_get_data_double(maskslits, "ybottom");
01264
01265
01266
01267
01268
01269
01270 coeff = cpl_table_new(nslits);
01271 cpl_table_copy_structure(coeff, ids);
01272 cpl_table_new_column(coeff, "xccd", CPL_TYPE_DOUBLE);
01273 cpl_table_new_column(coeff, "yccd", CPL_TYPE_DOUBLE);
01274 cpl_table_new_column(coeff, "xmask", CPL_TYPE_DOUBLE);
01275 cpl_table_new_column(coeff, "ymask", CPL_TYPE_DOUBLE);
01276
01277 for (i = 0; i < nslits; i++) {
01278 for (j = 0; j < nmaskslits; j++) {
01279 if (slit_id[i] == mslit_id[j]) {
01280 cpl_table_set_double(coeff, "xmask", i,
01281 (mxtop[j] + mxbottom[j]) / 2);
01282 cpl_table_set_double(coeff, "ymask", i,
01283 (mytop[j] + mybottom[j]) / 2);
01284 }
01285 }
01286 }
01287
01288 if (cpl_table_has_invalid(coeff, "xmask")) {
01289 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
01290 cpl_table_delete(coeff);
01291 return NULL;
01292 }
01293
01294 for (i = 0; i < nslits; i++) {
01295 cpl_table_set_double(coeff, "xccd", i, (xtop[i] + xbottom[i]) / 2);
01296 cpl_table_set_double(coeff, "yccd", i, (ytop[i] + ybottom[i]) / 2);
01297 }
01298
01299 for (i = 0; i < nslits; i++) {
01300
01301 if (length[i] == 0)
01302 continue;
01303
01304 cpl_table_and_selected_window(ids, position[i], length[i]);
01305 dummy = cpl_table_extract_selected(ids);
01306 for (j = 0; j < 6; j++) {
01307 if (cpl_table_has_column(dummy, clab[j])) {
01308 if (length[i] - cpl_table_count_invalid(dummy, clab[j]) > 10) {
01309 cpl_table_set_double(coeff, clab[j], i,
01310 cpl_table_get_column_median(dummy, clab[j]));
01311 }
01312 }
01313 }
01314
01315 cpl_table_delete(dummy);
01316 cpl_table_select_all(ids);
01317
01318 }
01319
01320 for (j = 0; j < 6; j++) {
01321 if (cpl_table_has_column(coeff, clab[j])) {
01322 cpl_table_and_selected_invalid(coeff, clab[j]);
01323
01324 if (cpl_table_not_selected(coeff))
01325 dummy = cpl_table_extract_selected(coeff);
01326 else
01327 break;
01328
01329 npoints = cpl_table_get_nrow(dummy);
01330
01331 if (npoints >= 6) {
01332
01333 if (npoints >= 12)
01334 order = 2;
01335 else
01336 order = 1;
01337
01338 ci = cpl_vector_wrap(npoints,
01339 cpl_table_get_data_double(dummy, clab[j]));
01340 if (j) {
01341 xccd = cpl_vector_wrap(npoints,
01342 cpl_table_get_data_double(dummy, "xccd"));
01343 yccd = cpl_vector_wrap(npoints,
01344 cpl_table_get_data_double(dummy, "yccd"));
01345 ccd = cpl_bivector_wrap_vectors(xccd, yccd);
01346
01347
01348 poly = cpl_polynomial_fit_2d_create(ccd, ci, order, NULL);
01349
01350 cpl_bivector_unwrap_vectors(ccd);
01351 cpl_vector_unwrap(xccd);
01352 cpl_vector_unwrap(yccd);
01353 cpl_vector_unwrap(ci);
01354 }
01355 else {
01356 xmask = cpl_vector_wrap(npoints,
01357 cpl_table_get_data_double(dummy, "xmask"));
01358 ymask = cpl_vector_wrap(npoints,
01359 cpl_table_get_data_double(dummy, "ymask"));
01360 mask = cpl_bivector_wrap_vectors(xmask, ymask);
01361
01362
01363 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
01364
01365 cpl_bivector_unwrap_vectors(mask);
01366 cpl_vector_unwrap(xmask);
01367 cpl_vector_unwrap(ymask);
01368 cpl_vector_unwrap(ci);
01369 }
01370 }
01371 else {
01372 cpl_size p[2] = {0, 0};
01373 poly = cpl_polynomial_new(2);
01374 cpl_polynomial_set_coeff(poly, p,
01375 cpl_table_get_column_median(dummy, clab[j]));
01376 }
01377
01378 cpl_table_delete(dummy);
01379
01380 global = write_global_distortion(global, j, poly);
01381
01382 cpl_polynomial_delete(poly);
01383
01384 cpl_table_select_all(coeff);
01385 }
01386 }
01387
01388 cpl_table_delete(coeff);
01389
01390
01391
01392
01393
01394
01395 cpl_table_set_double(global, "a00", 6, reference);
01396
01397
01398
01399
01400
01401
01402 coeff = cpl_table_duplicate(crv);
01403 cpl_table_new_column(coeff, "xmask", CPL_TYPE_DOUBLE);
01404 cpl_table_new_column(coeff, "ymask", CPL_TYPE_DOUBLE);
01405 cpl_table_new_column(coeff, "xccd", CPL_TYPE_DOUBLE);
01406 cpl_table_new_column(coeff, "yccd", CPL_TYPE_DOUBLE);
01407 slit_id = cpl_table_get_data_int(coeff, "slit_id");
01408 npoints = cpl_table_get_nrow(coeff);
01409
01410 for (i = 0; i < npoints; i++) {
01411 for (j = 0; j < nmaskslits; j++) {
01412 if (slit_id[i] == mslit_id[j]) {
01413 if (i%2) {
01414 cpl_table_set_double(coeff, "xmask", i, mxbottom[j]);
01415 cpl_table_set_double(coeff, "ymask", i, mybottom[j]);
01416 }
01417 else {
01418 cpl_table_set_double(coeff, "xmask", i, mxtop[j]);
01419 cpl_table_set_double(coeff, "ymask", i, mytop[j]);
01420 }
01421 }
01422 }
01423 if (i%2)
01424 {
01425 cpl_table_set_double(coeff, "xccd", i, xtop[(i-1)/2]);
01426 cpl_table_set_double(coeff, "yccd", i, ytop[(i-1)/2]);
01427 }
01428 else
01429 {
01430 cpl_table_set_double(coeff, "xccd", i, xbottom[i/2]);
01431 cpl_table_set_double(coeff, "yccd", i, ybottom[i/2]);
01432 }
01433 }
01434
01435 if (cpl_table_has_invalid(coeff, "xmask")) {
01436 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
01437 cpl_table_delete(coeff);
01438 return NULL;
01439 }
01440
01441 for (j = 0; j < 3; j++) {
01442 cpl_polynomial * poly_ccd;
01443 if (cpl_table_has_column(coeff, clab[j])) {
01444 cpl_table_and_selected_invalid(coeff, clab[j]);
01445
01446 if (cpl_table_not_selected(coeff))
01447 dummy = cpl_table_extract_selected(coeff);
01448 else
01449 break;
01450
01451 npoints = cpl_table_get_nrow(dummy);
01452
01453 if (npoints >= 6) {
01454
01455 if (npoints >= 12)
01456 order = 2;
01457 else
01458 order = 1;
01459
01460 ci = cpl_vector_wrap(npoints,
01461 cpl_table_get_data_double(dummy, clab[j]));
01462 xmask = cpl_vector_wrap(npoints,
01463 cpl_table_get_data_double(dummy, "xmask"));
01464 ymask = cpl_vector_wrap(npoints,
01465 cpl_table_get_data_double(dummy, "ymask"));
01466 mask = cpl_bivector_wrap_vectors(xmask, ymask);
01467
01468 poly = cpl_polynomial_fit_2d_create(mask, ci, order, NULL);
01469
01470 xccd = cpl_vector_wrap(npoints,
01471 cpl_table_get_data_double(dummy, "xccd"));
01472 yccd = cpl_vector_wrap(npoints,
01473 cpl_table_get_data_double(dummy, "yccd"));
01474 ccd = cpl_bivector_wrap_vectors(xccd, yccd);
01475
01476 poly_ccd = cpl_polynomial_fit_2d_create(ccd, ci, order, NULL);
01477
01478
01479 cpl_bivector_unwrap_vectors(mask);
01480 cpl_vector_unwrap(ci);
01481 cpl_vector_unwrap(xmask);
01482 cpl_vector_unwrap(ymask);
01483 }
01484 else {
01485 cpl_size p[2] = {0, 0};
01486 poly = cpl_polynomial_new(2);
01487 cpl_polynomial_set_coeff(poly, p,
01488 cpl_table_get_column_median(dummy, clab[j]));
01489 }
01490
01491 cpl_table_delete(dummy);
01492
01493 global = write_global_distortion(global, j + 7, poly);
01494 global = write_global_distortion(global, j + 10, poly_ccd);
01495
01496 cpl_polynomial_delete(poly);
01497 cpl_polynomial_delete(poly_ccd);
01498 cpl_table_select_all(coeff);
01499 }
01500 }
01501
01502 cpl_table_delete(coeff);
01503
01504 return global;
01505
01506 }
01507
01508
01546 cpl_table *mos_build_slit_location(cpl_table *global, cpl_table *maskslits,
01547 int ysize)
01548 {
01549 const char *func = "mos_build_slit_location";
01550
01551 cpl_propertylist *sort_col;
01552 cpl_polynomial *ids0;
01553 cpl_polynomial *crv[3];
01554 cpl_polynomial *loc_crv;
01555 cpl_vector *point;
01556 cpl_table *slits;
01557 cpl_size nslits;
01558 int *slit_id;
01559 double *dpoint;
01560 double *xtop;
01561 double *ytop;
01562 double *xbottom;
01563 double *ybottom;
01564 double *mxtop;
01565 double *mytop;
01566 double *mxbottom;
01567 double *mybottom;
01568 cpl_size i;
01569 cpl_size j;
01570
01571
01572 if (global == NULL || maskslits == NULL) {
01573 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01574 return NULL;
01575 }
01576
01577 nslits = cpl_table_get_nrow(maskslits);
01578 slit_id = cpl_table_get_data_int(maskslits, "slit_id");
01579 mxtop = cpl_table_get_data_double(maskslits, "xtop");
01580 mytop = cpl_table_get_data_double(maskslits, "ytop");
01581 mxbottom = cpl_table_get_data_double(maskslits, "xbottom");
01582 mybottom = cpl_table_get_data_double(maskslits, "ybottom");
01583
01584 slits = cpl_table_duplicate(maskslits);
01585
01586 xtop = cpl_table_get_data_double(slits, "xtop");
01587 ytop = cpl_table_get_data_double(slits, "ytop");
01588 xbottom = cpl_table_get_data_double(slits, "xbottom");
01589 ybottom = cpl_table_get_data_double(slits, "ybottom");
01590
01591 ids0 = read_global_distortion(global, 0);
01592 crv[0] = read_global_distortion(global, 7);
01593 crv[1] = read_global_distortion(global, 8);
01594 crv[2] = read_global_distortion(global, 9);
01595
01596 loc_crv = cpl_polynomial_new(1);
01597
01598 point = cpl_vector_new(2);
01599 dpoint = cpl_vector_get_data(point);
01600
01601 for (i = 0; i < nslits; i++) {
01602 dpoint[0] = mxtop[i];
01603 dpoint[1] = mytop[i];
01604
01605 xtop[i] = cpl_polynomial_eval(ids0, point);
01606
01607 for (j = 0; j < 3; j++)
01608 if (crv[j])
01609 cpl_polynomial_set_coeff(loc_crv, &j,
01610 cpl_polynomial_eval(crv[j], point));
01611
01612 ytop[i] = cpl_polynomial_eval_1d(loc_crv, xtop[i], NULL);
01613
01614 dpoint[0] = mxbottom[i];
01615 dpoint[1] = mybottom[i];
01616 xbottom[i] = cpl_polynomial_eval(ids0, point);
01617
01618 for (j = 0; j < 3; j++)
01619 if (crv[j])
01620 cpl_polynomial_set_coeff(loc_crv, &j,
01621 cpl_polynomial_eval(crv[j], point));
01622
01623 ybottom[i] = cpl_polynomial_eval_1d(loc_crv, xbottom[i], NULL);
01624 }
01625
01626 cpl_vector_delete(point);
01627 cpl_polynomial_delete(ids0);
01628 cpl_polynomial_delete(loc_crv);
01629 for (j = 0; j < 3; j++)
01630 cpl_polynomial_delete(crv[j]);
01631
01632 sort_col = cpl_propertylist_new();
01633 cpl_propertylist_append_bool(sort_col, "ytop", 1);
01634 cpl_table_sort(slits, sort_col);
01635 cpl_table_sort(maskslits, sort_col);
01636 cpl_propertylist_delete(sort_col);
01637
01638
01639
01640
01641
01642 cpl_table_and_selected_double(slits, "ybottom", CPL_GREATER_THAN, ysize-1);
01643 cpl_table_or_selected_double(slits, "ytop", CPL_LESS_THAN, 0);
01644 cpl_table_erase_selected(slits);
01645
01646 nslits = cpl_table_get_nrow(slits);
01647
01648 if (nslits == 0) {
01649 cpl_msg_warning(func, "No slits found on the CCD");
01650 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
01651 cpl_table_delete(slits);
01652 return NULL;
01653 }
01654
01655 if (nslits > 1)
01656 cpl_msg_info(func, "Slit location: %"CPL_SIZE_FORMAT" slits are entirely or partially "
01657 "contained in CCD", nslits);
01658 else
01659 cpl_msg_info(func, "Slit location: %"CPL_SIZE_FORMAT" slit is entirely or partially "
01660 "contained in CCD", nslits);
01661
01662 return slits;
01663
01664 }
01665
01666
01693 cpl_table *mos_build_curv_coeff(cpl_table *global, cpl_table *maskslits,
01694 cpl_table *slits)
01695 {
01696 const char *func = "mos_build_curv_coeff";
01697
01698 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01699
01700
01701 cpl_polynomial *crv[3];
01702 cpl_vector *point;
01703 cpl_table *polytraces;
01704 double *dpoint;
01705 double *xtop;
01706 double *ytop;
01707 double *xbottom;
01708 double *ybottom;
01709 int *slit_id;
01710 int *valid_id;
01711 int nslits, nvalid;
01712 int found;
01713 int i, j, k;
01714
01715
01716 if (global == NULL || slits == NULL || maskslits == NULL) {
01717 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01718 return NULL;
01719 }
01720
01721 nslits = cpl_table_get_nrow(maskslits);
01722 slit_id = cpl_table_get_data_int(maskslits, "slit_id");
01723 xtop = cpl_table_get_data_double(maskslits, "xtop");
01724 ytop = cpl_table_get_data_double(maskslits, "ytop");
01725 xbottom = cpl_table_get_data_double(maskslits, "xbottom");
01726 ybottom = cpl_table_get_data_double(maskslits, "ybottom");
01727
01728 polytraces = cpl_table_new(2*nslits);
01729 cpl_table_new_column(polytraces, "slit_id", CPL_TYPE_INT);
01730 for (i = 0; i < 3; i++)
01731 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
01732
01733 crv[0] = read_global_distortion(global, 7);
01734 crv[1] = read_global_distortion(global, 8);
01735 crv[2] = read_global_distortion(global, 9);
01736
01737 point = cpl_vector_new(2);
01738 dpoint = cpl_vector_get_data(point);
01739
01740 for (i = 0; i < nslits; i++) {
01741 for (j = 0; j < 2; j++) {
01742
01743 cpl_table_set_int(polytraces, "slit_id", 2*i+j, slit_id[i]);
01744
01745 if (j) {
01746 dpoint[0] = xbottom[i];
01747 dpoint[1] = ybottom[i];
01748 }
01749 else {
01750 dpoint[0] = xtop[i];
01751 dpoint[1] = ytop[i];
01752 }
01753
01754 for (k = 0; k < 3; k++)
01755 if (crv[j])
01756 cpl_table_set_double(polytraces, clab[k], 2*i+j,
01757 cpl_polynomial_eval(crv[k], point));
01758 }
01759 }
01760
01761 cpl_vector_delete(point);
01762 for (j = 0; j < 3; j++)
01763 cpl_polynomial_delete(crv[j]);
01764
01765
01766
01767
01768
01769 nvalid = cpl_table_get_nrow(slits);
01770 valid_id = cpl_table_get_data_int(slits, "slit_id");
01771 cpl_table_unselect_all(polytraces);
01772 for (i = 0; i < nslits; i++) {
01773 found = 0;
01774 for (j = 0; j < nvalid; j++) {
01775 if (slit_id[i] == valid_id[j]) {
01776 found = 1;
01777 break;
01778 }
01779 }
01780 if (!found) {
01781 cpl_table_select_row(polytraces, 2*i);
01782 cpl_table_select_row(polytraces, 2*i + 1);
01783 }
01784 }
01785 cpl_table_erase_selected(polytraces);
01786
01787 nslits = cpl_table_get_nrow(polytraces);
01788
01789 if (nslits == 0) {
01790 cpl_msg_warning(func, "No slits found on the CCD");
01791 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
01792 cpl_table_delete(polytraces);
01793 return NULL;
01794 }
01795
01796 if (nslits > 2)
01797 cpl_msg_info(func, "Curvature model: %d slits are entirely or "
01798 "partially contained in CCD", nslits / 2);
01799 else
01800 cpl_msg_info(func, "Curvature model: %d slit is entirely or "
01801 "partially contained in CCD", nslits / 2);
01802
01803 return polytraces;
01804 }
01805
01806
01848 cpl_table *mos_build_disp_coeff(cpl_table *global, cpl_table *slits)
01849 {
01850 const char *func = "mos_build_disp_coeff";
01851
01852 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01853
01854 cpl_polynomial *ids[6];
01855 cpl_vector *point;
01856 cpl_table *idscoeff;
01857 double *dpoint;
01858 double *xtop;
01859 double *ytop;
01860 double *xbottom;
01861 double *ybottom;
01862 int *position;
01863 int *length;
01864 int nslits;
01865 int nrows;
01866 int order;
01867 int ylow, yhig;
01868 int i, j, k;
01869
01870
01871 if (global == NULL || slits == NULL) {
01872 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
01873 return NULL;
01874 }
01875
01876 nslits = cpl_table_get_nrow(slits);
01877 position = cpl_table_get_data_int(slits, "position");
01878 length = cpl_table_get_data_int(slits, "length");
01879 xtop = cpl_table_get_data_double(slits, "xtop");
01880 ytop = cpl_table_get_data_double(slits, "ytop");
01881 xbottom = cpl_table_get_data_double(slits, "xbottom");
01882 ybottom = cpl_table_get_data_double(slits, "ybottom");
01883
01884 for (i = 0; i < 6; i++)
01885 ids[i] = read_global_distortion(global, i);
01886
01887 for (i = 0; i < 6; i++)
01888 if (ids[i] == NULL)
01889 break;
01890
01891 order = i - 1;
01892
01893 if (order < 1) {
01894 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
01895 return NULL;
01896 }
01897
01898 nrows = 0;
01899 for (i = 0; i < nslits; i++)
01900 nrows += length[i];
01901
01902 idscoeff = cpl_table_new(nrows);
01903
01904 for (j = 0; j <= order; j++)
01905 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
01906
01907 cpl_table_new_column(idscoeff, "error", CPL_TYPE_DOUBLE);
01908 cpl_table_fill_column_window_double(idscoeff, "error", 0, nrows, 0.0);
01909 cpl_table_new_column(idscoeff, "nlines", CPL_TYPE_INT);
01910 cpl_table_fill_column_window_int(idscoeff, "nlines", 0, nrows, 0);
01911
01912 point = cpl_vector_new(2);
01913 dpoint = cpl_vector_get_data(point);
01914
01915 for (i = 0; i < nslits; i++) {
01916
01917 if (length[i] == 0)
01918 continue;
01919
01920 ylow = position[i];
01921 yhig = ylow + length[i];
01922
01923 for (j = 0; j <= order; j++) {
01924 if (j) {
01925 for (k = 0; k < length[i]; k++) {
01926 dpoint[0] = xbottom[i] + k*(xtop[i]-xbottom[i])/length[i];
01927 dpoint[1] = ybottom[i] + k*(ytop[i]-ybottom[i])/length[i];
01928 cpl_table_set_double(idscoeff, clab[j], ylow + k,
01929 cpl_polynomial_eval(ids[j], point));
01930 }
01931 }
01932 else {
01933 for (k = 0; k < length[i]; k++) {
01934 cpl_table_set_double(idscoeff, clab[0], ylow + k,
01935 xbottom[i] + k*(xtop[i]-xbottom[i])/length[i]);
01936 }
01937 }
01938 }
01939 }
01940
01941 cpl_vector_delete(point);
01942 for (j = 0; j < 6; j++)
01943 cpl_polynomial_delete(ids[j]);
01944
01945 return idscoeff;
01946
01947 }
01948
01949
01972 cpl_image *mos_subtract_sky(cpl_image *science, cpl_table *slits,
01973 cpl_table *polytraces, double reference,
01974 double blue, double red, double dispersion)
01975 {
01976 const char *func = "mos_subtract_sky";
01977
01978 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
01979
01980
01981 cpl_image *sky;
01982 cpl_bivector *list;
01983 cpl_vector *listx;
01984 cpl_vector *listy;
01985 cpl_polynomial *polytop;
01986 cpl_polynomial *polybot;
01987 cpl_polynomial *trend;
01988
01989 int *slit_id;
01990 double *dlistx;
01991 double *dlisty;
01992 float *sdata;
01993 float *kdata;
01994 double top, bot;
01995 int itop, ibot;
01996 double coeff;
01997 double ytop, ybot;
01998 double m, q, err;
01999 int npix;
02000
02001 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
02002 int nx, ny;
02003 int nslits;
02004 int *length;
02005 int missing_top, missing_bot;
02006 int order;
02007 int null;
02008 int window = 50;
02009 int count;
02010 int i, j;
02011 cpl_size k;
02012
02013
02014 if (science == NULL || slits == NULL || polytraces == NULL) {
02015 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02016 return NULL;
02017 }
02018
02019 if (dispersion <= 0.0) {
02020 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02021 return NULL;
02022 }
02023
02024 if (red - blue < dispersion) {
02025 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02026 return NULL;
02027 }
02028
02029 nx = cpl_image_get_size_x(science);
02030 ny = cpl_image_get_size_y(science);
02031
02032 sky = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
02033
02034 sdata = cpl_image_get_data(science);
02035 kdata = cpl_image_get_data(sky);
02036
02037 nslits = cpl_table_get_nrow(slits);
02038 order = cpl_table_get_ncol(polytraces) - 2;
02039 length = cpl_table_get_data_int(slits, "length");
02040 slit_id = cpl_table_get_data_int(slits, "slit_id");
02041
02042
02043
02044
02045
02046
02047 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
02048 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
02049
02050 for (i = 0; i < nslits; i++) {
02051
02052 if (length[i] == 0)
02053 continue;
02054
02055
02056
02057
02058
02059
02060
02061 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
02062
02063 start_pixel = refpixel - pixel_below;
02064 if (start_pixel < 0)
02065 start_pixel = 0;
02066
02067 end_pixel = refpixel + pixel_above;
02068 if (end_pixel > nx)
02069 end_pixel = nx;
02070
02071 missing_top = 0;
02072 polytop = cpl_polynomial_new(1);
02073 for (k = 0; k <= order; k++) {
02074 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
02075 if (null) {
02076 cpl_polynomial_delete(polytop);
02077 missing_top = 1;
02078 break;
02079 }
02080 cpl_polynomial_set_coeff(polytop, &k, coeff);
02081 }
02082
02083 missing_bot = 0;
02084 polybot = cpl_polynomial_new(1);
02085 for (k = 0; k <= order; k++) {
02086 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
02087 if (null) {
02088 cpl_polynomial_delete(polybot);
02089 missing_bot = 1;
02090 break;
02091 }
02092 cpl_polynomial_set_coeff(polybot, &k, coeff);
02093 }
02094
02095 if (missing_top && missing_bot) {
02096 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
02097 slit_id[i]);
02098 continue;
02099 }
02100
02101
02102
02103
02104
02105
02106
02107 if (missing_top) {
02108 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
02109 "the spectral curvature of the lower edge "
02110 "is used instead.", slit_id[i]);
02111 polytop = cpl_polynomial_duplicate(polybot);
02112 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02113 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02114 k = 0;
02115 coeff = cpl_polynomial_get_coeff(polybot, &k);
02116 coeff += ytop - ybot;
02117 cpl_polynomial_set_coeff(polytop, &k, coeff);
02118 }
02119
02120 if (missing_bot) {
02121 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
02122 "the spectral curvature of the upper edge "
02123 "is used instead.", slit_id[i]);
02124 polybot = cpl_polynomial_duplicate(polytop);
02125 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02126 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02127 k = 0;
02128 coeff = cpl_polynomial_get_coeff(polytop, &k);
02129 coeff -= ytop - ybot;
02130 cpl_polynomial_set_coeff(polybot, &k, coeff);
02131 }
02132
02133
02134
02135
02136
02137
02138 for (j = start_pixel; j < end_pixel; j++) {
02139 top = cpl_polynomial_eval_1d(polytop, j, NULL);
02140 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
02141 itop = floor(top + 0.5) + 1;
02142 ibot = floor(bot + 0.5);
02143 if (itop > ny)
02144 itop = ny;
02145 if (ibot < 0)
02146 ibot = 0;
02147 npix = itop - ibot;
02148 if (npix < 5)
02149 break;
02150
02151 list = cpl_bivector_new(npix);
02152 listx = cpl_bivector_get_x(list);
02153 listy = cpl_bivector_get_y(list);
02154 dlistx = cpl_vector_get_data(listx);
02155 dlisty = cpl_vector_get_data(listy);
02156
02157 for (k = 0; k < npix; k++) {
02158 dlistx[k] = k;
02159 dlisty[k] = sdata[j + (ibot + k)*nx];
02160 }
02161
02162 if (robustLinearFit(list, &q, &m, &err)) {
02163 cpl_bivector_delete(list);
02164 continue;
02165 }
02166
02167 cpl_bivector_delete(list);
02168
02169 for (k = 0; k < npix; k++) {
02170 kdata[j + (ibot + k)*nx] = m*k + q;
02171 }
02172
02173 if (npix > window) {
02174
02175
02176
02177
02178
02179 err = 3*sqrt(err);
02180
02181 count = 0;
02182 for (k = 0; k < npix; k++)
02183 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err)
02184 count++;
02185
02186 if (count < 10)
02187 continue;
02188
02189 list = cpl_bivector_new(count);
02190 listx = cpl_bivector_get_x(list);
02191 listy = cpl_bivector_get_y(list);
02192 dlistx = cpl_vector_get_data(listx);
02193 dlisty = cpl_vector_get_data(listy);
02194
02195 count = 0;
02196 for (k = 0; k < npix; k++) {
02197 if (fabs(sdata[j + (ibot + k)*nx] - m*k - q) < err) {
02198 dlistx[count] = k;
02199 dlisty[count] = sdata[j + (ibot + k)*nx];
02200 count++;
02201 }
02202 }
02203
02204 trend = cpl_polynomial_fit_1d_create(listx, listy, 2, &err);
02205
02206 cpl_bivector_delete(list);
02207
02208 err = 3*sqrt(err);
02209
02210 count = 0;
02211 for (k = 0; k < npix; k++)
02212 if (fabs(sdata[j + (ibot + k)*nx]
02213 - cpl_polynomial_eval_1d(trend, k, NULL)) < err)
02214 count++;
02215
02216 if (count < 10) {
02217 cpl_polynomial_delete(trend);
02218 continue;
02219 }
02220
02221 list = cpl_bivector_new(count);
02222 listx = cpl_bivector_get_x(list);
02223 listy = cpl_bivector_get_y(list);
02224 dlistx = cpl_vector_get_data(listx);
02225 dlisty = cpl_vector_get_data(listy);
02226
02227 count = 0;
02228 for (k = 0; k < npix; k++) {
02229 if (fabs(sdata[j + (ibot + k)*nx]
02230 - cpl_polynomial_eval_1d(trend, k, NULL)) < err) {
02231 dlistx[count] = k;
02232 dlisty[count] = sdata[j + (ibot + k)*nx];
02233 count++;
02234 }
02235 }
02236
02237 cpl_polynomial_delete(trend);
02238
02239 trend = cpl_polynomial_fit_1d_create(listx, listy, 3, &err);
02240
02241 cpl_bivector_delete(list);
02242
02243 for (k = 0; k < npix; k++) {
02244 kdata[j + (ibot + k)*nx] = cpl_polynomial_eval_1d(trend,
02245 k, NULL);
02246 }
02247
02248 cpl_polynomial_delete(trend);
02249 }
02250 }
02251 cpl_polynomial_delete(polytop);
02252 cpl_polynomial_delete(polybot);
02253 }
02254
02255 cpl_image_subtract(science, sky);
02256
02257 return sky;
02258 }
02259
02260
02293 cpl_image *mos_normalise_flat(cpl_image *flat, cpl_image *spatial,
02294 cpl_table *slits, cpl_table *polytraces,
02295 double reference, double blue, double red,
02296 double dispersion, int sradius, int polyorder)
02297 {
02298 const char *func = "mos_normalise_flat";
02299
02300 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
02301
02302
02303 cpl_image *rectified;
02304 cpl_image *smo_flat;
02305 cpl_image *exslit;
02306 cpl_vector *positions;
02307 cpl_vector *flux;
02308 cpl_vector *smo_flux;
02309 cpl_polynomial *trend;
02310 cpl_polynomial *polytop;
02311 cpl_polynomial *polybot;
02312
02313 int *slit_id;
02314 float *p;
02315 float *data;
02316 double *fdata;
02317 double *pdata;
02318 float *sdata;
02319 float *xdata;
02320 float *wdata;
02321 double vtop, vbot, value;
02322 double top, bot;
02323 double coeff;
02324 double ytop, ybot;
02325 double ypos;
02326 double fvalue;
02327 int ivalue;
02328 int yint, yprev;
02329 int npseudo;
02330
02331 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
02332 int nx, ny, nsubx, nsuby;
02333 int xlow, ylow, xhig, yhig;
02334 int nslits;
02335 int *position;
02336 int *length;
02337 int missing_top, missing_bot;
02338 int order;
02339 int npoints;
02340 int uradius;
02341 int null;
02342 int i, j;
02343 cpl_size k;
02344
02345
02346
02347
02348
02349
02350 if (flat == NULL || slits == NULL || polytraces == NULL) {
02351 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02352 return NULL;
02353 }
02354
02355 if (dispersion <= 0.0) {
02356 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02357 return NULL;
02358 }
02359
02360 if (red - blue < dispersion) {
02361 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02362 return NULL;
02363 }
02364
02365 rectified = mos_spatial_calibration(flat, slits, polytraces, reference,
02366 blue, red, dispersion, 0, NULL);
02367
02368 nx = cpl_image_get_size_x(rectified);
02369 ny = cpl_image_get_size_y(rectified);
02370
02371 smo_flat = cpl_image_new(cpl_image_get_size_x(spatial),
02372 cpl_image_get_size_y(spatial), CPL_TYPE_FLOAT);
02373 wdata = cpl_image_get_data(smo_flat);
02374
02375 nslits = cpl_table_get_nrow(slits);
02376 order = cpl_table_get_ncol(polytraces) - 2;
02377 position = cpl_table_get_data_int(slits, "position");
02378 length = cpl_table_get_data_int(slits, "length");
02379 slit_id = cpl_table_get_data_int(slits, "slit_id");
02380
02381
02382
02383
02384
02385
02386 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
02387 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
02388
02389 xlow = 1;
02390 xhig = nx;
02391 for (i = 0; i < nslits; i++) {
02392
02393 if (length[i] == 0)
02394 continue;
02395
02396
02397
02398
02399
02400
02401
02402
02403
02404
02405
02406 ylow = position[i] + 1;
02407 yhig = ylow + length[i] - 1;
02408
02409 exslit = cpl_image_extract(rectified, xlow, ylow, xhig, yhig);
02410
02411 if (polyorder < 0) {
02412
02413 cpl_image_turn(exslit, -1);
02414
02415 nsubx = cpl_image_get_size_x(exslit);
02416 nsuby = cpl_image_get_size_y(exslit);
02417 data = cpl_image_get_data(exslit);
02418 flux = cpl_vector_new(nsubx);
02419
02420 uradius = nsubx / 2;
02421 if (uradius > sradius)
02422 uradius = sradius;
02423
02424 for (j = 0; j < nsuby; j++) {
02425 fdata = cpl_vector_get_data(flux);
02426 p = data;
02427 for (k = 0; k < nsubx; k++)
02428 *fdata++ = *p++;
02429 smo_flux = cpl_vector_filter_median_create(flux, uradius);
02430 fdata = cpl_vector_get_data(smo_flux);
02431 p = data;
02432 for (k = 0; k < nsubx; k++)
02433 *p++ = *fdata++;
02434 cpl_vector_delete(smo_flux);
02435 data += nsubx;
02436 }
02437
02438 cpl_vector_delete(flux);
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
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474 cpl_image_turn(exslit, 1);
02475 nsubx = cpl_image_get_size_x(exslit);
02476 nsuby = cpl_image_get_size_y(exslit);
02477 data = cpl_image_get_data(exslit);
02478
02479 for (j = 0; j < nsuby; j++) {
02480 flux = cpl_vector_new(nsubx);
02481 fdata = cpl_vector_get_data(flux);
02482 p = data;
02483 for (k = 0; k < nsubx; k++)
02484 *fdata++ = *p++;
02485 smo_flux = cpl_vector_filter_median_create(flux, sradius);
02486 cpl_vector_delete(flux);
02487 fdata = cpl_vector_get_data(smo_flux);
02488 p = data;
02489 for (k = 0; k < nsubx; k++)
02490 *p++ = *fdata++;
02491 cpl_vector_delete(smo_flux);
02492 data += nsubx;
02493 }
02494 }
02495 else {
02496
02497
02498
02499
02500
02501 nsubx = cpl_image_get_size_x(exslit);
02502 nsuby = cpl_image_get_size_y(exslit);
02503 data = cpl_image_get_data(exslit);
02504
02505 for (j = 0; j < nsuby; j++) {
02506
02507
02508
02509
02510
02511 npoints = 0;
02512 p = data + j*nsubx;
02513 for (k = 0; k < nsubx; k++)
02514 if (p[k] > 1.0)
02515 npoints++;
02516
02517 if (npoints > polyorder + 1) {
02518
02519
02520
02521
02522
02523 flux = cpl_vector_new(npoints);
02524 fdata = cpl_vector_get_data(flux);
02525 positions = cpl_vector_new(npoints);
02526 pdata = cpl_vector_get_data(positions);
02527
02528 npoints = 0;
02529 p = data + j*nsubx;
02530 for (k = 0; k < nsubx; k++) {
02531 if (p[k] > 1.0) {
02532 fdata[npoints] = p[k];
02533 pdata[npoints] = k;
02534 npoints++;
02535 }
02536 }
02537
02538 trend = cpl_polynomial_fit_1d_create(positions, flux,
02539 polyorder, NULL);
02540
02541 cpl_vector_delete(flux);
02542 cpl_vector_delete(positions);
02543
02544 if (trend) {
02545 p = data + j*nsubx;
02546 for (k = 0; k < nsubx; k++)
02547 if (p[k] > 1.0)
02548 p[k] = cpl_polynomial_eval_1d(trend, k, NULL);
02549 cpl_polynomial_delete(trend);
02550 }
02551 else {
02552 cpl_msg_warning(func, "Invalid flat field flux fit "
02553 "(ignored)");
02554 }
02555 }
02556 }
02557 }
02558
02559
02560
02561
02562
02563
02564
02565 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
02566
02567 start_pixel = refpixel - pixel_below;
02568 if (start_pixel < 0)
02569 start_pixel = 0;
02570
02571 end_pixel = refpixel + pixel_above;
02572 if (end_pixel > nx)
02573 end_pixel = nx;
02574
02575 missing_top = 0;
02576 polytop = cpl_polynomial_new(1);
02577 for (k = 0; k <= order; k++) {
02578 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
02579 if (null) {
02580 cpl_polynomial_delete(polytop);
02581 missing_top = 1;
02582 break;
02583 }
02584 cpl_polynomial_set_coeff(polytop, &k, coeff);
02585 }
02586
02587 missing_bot = 0;
02588 polybot = cpl_polynomial_new(1);
02589 for (k = 0; k <= order; k++) {
02590 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
02591 if (null) {
02592 cpl_polynomial_delete(polybot);
02593 missing_bot = 1;
02594 break;
02595 }
02596 cpl_polynomial_set_coeff(polybot, &k, coeff);
02597 }
02598
02599 if (missing_top && missing_bot) {
02600 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
02601 slit_id[i]);
02602 continue;
02603 }
02604
02605
02606
02607
02608
02609
02610
02611 if (missing_top) {
02612 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
02613 "the spectral curvature of the lower edge "
02614 "is used instead.", slit_id[i]);
02615 polytop = cpl_polynomial_duplicate(polybot);
02616 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02617 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02618 k = 0;
02619 coeff = cpl_polynomial_get_coeff(polybot, &k);
02620 coeff += ytop - ybot;
02621 cpl_polynomial_set_coeff(polytop, &k, coeff);
02622 }
02623
02624 if (missing_bot) {
02625 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
02626 "the spectral curvature of the upper edge "
02627 "is used instead.", slit_id[i]);
02628 polybot = cpl_polynomial_duplicate(polytop);
02629 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02630 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02631 k = 0;
02632 coeff = cpl_polynomial_get_coeff(polytop, &k);
02633 coeff -= ytop - ybot;
02634 cpl_polynomial_set_coeff(polybot, &k, coeff);
02635 }
02636
02637
02638
02639
02640
02641
02642
02643
02644
02645 nx = cpl_image_get_size_x(flat);
02646 ny = cpl_image_get_size_y(flat);
02647
02648 sdata = cpl_image_get_data(spatial);
02649 xdata = cpl_image_get_data(exslit);
02650 npseudo = cpl_image_get_size_y(exslit) - 1;
02651
02652
02653
02654
02655
02656 for (j = start_pixel; j < end_pixel; j++) {
02657 top = cpl_polynomial_eval_1d(polytop, j, NULL);
02658 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
02659 for (k = 0; k <= npseudo; k++) {
02660 ypos = top - k*(top-bot)/npseudo;
02661 yint = ypos;
02662
02663
02664
02665
02666
02667
02668
02669
02670 if (yint < 0 || yint >= ny-1) {
02671 yprev = yint;
02672 continue;
02673 }
02674
02675 value = sdata[j + nx*yint];
02676 ivalue = value;
02677 fvalue = value - ivalue;
02678 if (ivalue < npseudo && ivalue >= 0) {
02679 vtop = xdata[j + nx*(npseudo-ivalue)];
02680 vbot = xdata[j + nx*(npseudo-ivalue-1)];
02681 wdata[j + nx*yint] = vtop*(1-fvalue) + vbot*fvalue;
02682
02683 if (k) {
02684
02685
02686
02687
02688
02689
02690
02691 if (yprev - yint > 1) {
02692 value = sdata[j + nx*(yint+1)];
02693 ivalue = value;
02694 fvalue = value - ivalue;
02695 if (ivalue < npseudo && ivalue >= 0) {
02696 vtop = xdata[j + nx*(npseudo-ivalue)];
02697 vbot = xdata[j + nx*(npseudo-ivalue-1)];
02698 wdata[j + nx*(yint+1)] = vtop*(1-fvalue)
02699 + vbot*fvalue;
02700 }
02701 }
02702 }
02703 }
02704 yprev = yint;
02705 }
02706 }
02707 cpl_polynomial_delete(polytop);
02708 cpl_polynomial_delete(polybot);
02709 cpl_image_delete(exslit);
02710 }
02711
02712 cpl_image_delete(rectified);
02713
02714 cpl_image_divide(flat, smo_flat);
02715
02716 return smo_flat;
02717 }
02718
02719
02744 cpl_image *mos_normalise_longflat(cpl_image *flat, int sradius, int dradius,
02745 int polyorder)
02746 {
02747 const char *func = "mos_normalise_longflat";
02748
02749 cpl_image *smo_flat;
02750 cpl_image *profile;
02751 cpl_vector *flux;
02752 cpl_vector *smo_flux;
02753 cpl_vector *positions;
02754 cpl_polynomial *trend;
02755
02756 float *level;
02757 float *p;
02758 float *data;
02759 double *fdata;
02760 double *pdata;
02761
02762 int nx, ny;
02763 int npoints;
02764 int i, j;
02765
02766
02767 if (flat == NULL) {
02768 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
02769 return NULL;
02770 }
02771
02772 if (sradius < 1 || dradius < 1) {
02773 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
02774 return NULL;
02775 }
02776
02777 smo_flat = cpl_image_duplicate(flat);
02778
02779 if (polyorder < 0) {
02780
02781
02782
02783
02784
02785 cpl_image_turn(smo_flat, -1);
02786
02787 nx = cpl_image_get_size_x(smo_flat);
02788 ny = cpl_image_get_size_y(smo_flat);
02789 data = cpl_image_get_data(smo_flat);
02790
02791 for (i = 0; i < ny; i++) {
02792 flux = cpl_vector_new(nx);
02793 fdata = cpl_vector_get_data(flux);
02794 p = data;
02795 for (j = 0; j < nx; j++)
02796 *fdata++ = *p++;
02797 smo_flux = cpl_vector_filter_median_create(flux, sradius);
02798 cpl_vector_delete(flux);
02799 fdata = cpl_vector_get_data(smo_flux);
02800 p = data;
02801 for (j = 0; j < nx; j++)
02802 *p++ = *fdata++;
02803 cpl_vector_delete(smo_flux);
02804 data += nx;
02805 }
02806
02807
02808
02809
02810
02811 cpl_image_turn(smo_flat, 1);
02812
02813 nx = cpl_image_get_size_x(smo_flat);
02814 ny = cpl_image_get_size_y(smo_flat);
02815 data = cpl_image_get_data(smo_flat);
02816
02817 for (i = 0; i < ny; i++) {
02818 flux = cpl_vector_new(nx);
02819 fdata = cpl_vector_get_data(flux);
02820 p = data;
02821 for (j = 0; j < nx; j++)
02822 *fdata++ = *p++;
02823 smo_flux = cpl_vector_filter_median_create(flux, sradius);
02824 cpl_vector_delete(flux);
02825 fdata = cpl_vector_get_data(smo_flux);
02826 p = data;
02827 for (j = 0; j < nx; j++)
02828 *p++ = *fdata++;
02829 cpl_vector_delete(smo_flux);
02830 data += nx;
02831 }
02832 }
02833 else {
02834
02835
02836
02837
02838
02839 cpl_image_turn(smo_flat, -1);
02840
02841 nx = cpl_image_get_size_x(smo_flat);
02842 ny = cpl_image_get_size_y(smo_flat);
02843 data = cpl_image_get_data(smo_flat);
02844
02845 profile = cpl_image_collapse_median_create(smo_flat, 1, 0, 0);
02846 level = cpl_image_get_data(profile);
02847
02848 for (i = 0; i < ny; i++) {
02849
02850
02851
02852
02853
02854
02855
02856 npoints = 0;
02857 p = data + i*nx;
02858 for (j = 0; j < nx; j++)
02859 if (fabs(p[j]/level[i] - 1) < 0.20)
02860 npoints++;
02861
02862 if (npoints > polyorder + 1) {
02863
02864
02865
02866
02867
02868 flux = cpl_vector_new(npoints);
02869 fdata = cpl_vector_get_data(flux);
02870 positions = cpl_vector_new(npoints);
02871 pdata = cpl_vector_get_data(positions);
02872
02873 npoints = 0;
02874 p = data + i*nx;
02875 for (j = 0; j < nx; j++) {
02876 if (fabs(p[j]/level[i] - 1) < 0.20) {
02877 fdata[npoints] = p[j];
02878 pdata[npoints] = j;
02879 npoints++;
02880 }
02881 }
02882
02883 trend = cpl_polynomial_fit_1d_create(positions, flux,
02884 polyorder, NULL);
02885
02886 cpl_vector_delete(flux);
02887 cpl_vector_delete(positions);
02888
02889 if (trend) {
02890 p = data + i*nx;
02891 for (j = 0; j < nx; j++)
02892 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
02893 cpl_polynomial_delete(trend);
02894 }
02895 else {
02896 cpl_msg_warning(func,
02897 "Invalid flat field flux fit (ignored)");
02898 }
02899 }
02900 }
02901
02902 cpl_image_delete(profile);
02903 cpl_image_turn(smo_flat, 1);
02904
02905 }
02906
02907 cpl_image_divide(flat, smo_flat);
02908
02909 return smo_flat;
02910 }
02911
02912
02935 cpl_error_code mos_interpolate_wavecalib_slit(cpl_table *idscoeff,
02936 cpl_table *slits,
02937 int order, int global)
02938 {
02939 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
02940
02941 int nrow = cpl_table_get_nrow(slits);
02942 int i, j;
02943
02944
02945 if (order < 0)
02946 return CPL_ERROR_NONE;
02947
02948 cpl_table_new_column(idscoeff, "x", CPL_TYPE_DOUBLE);
02949 cpl_table_new_column(idscoeff, "y", CPL_TYPE_DOUBLE);
02950
02951 for (i = 0; i < nrow; i++) {
02952 int position = cpl_table_get_int (slits, "position", i, NULL);
02953 int length = cpl_table_get_int (slits, "length", i, NULL);
02954 double xtop = cpl_table_get_double(slits, "xtop", i, NULL);
02955 double xbot = cpl_table_get_double(slits, "xbottom", i, NULL);
02956 double ytop = cpl_table_get_double(slits, "ytop", i, NULL);
02957 double ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
02958 double dx = xtop - xbot;
02959 double dy = ytop - ybot;
02960 cpl_table *table = cpl_table_extract(idscoeff, position, length);
02961
02962 if (mos_interpolate_wavecalib(table, NULL, 2, order))
02963 continue;
02964
02965 cpl_table_erase_window(idscoeff, position, length);
02966 cpl_table_insert(idscoeff, table, position);
02967
02968 cpl_table_delete(table);
02969
02970 for (j = 0; j < length; j++) {
02971 cpl_table_set_double(idscoeff, "x", j + position,
02972 xbot + j*(dx/length));
02973 cpl_table_set_double(idscoeff, "y", j + position,
02974 ybot + j*(dy/length));
02975 }
02976 }
02977
02978 if (global) {
02979
02980
02981
02982
02983
02984 nrow = cpl_table_get_nrow(idscoeff);
02985
02986 for (i = 0; i < 6; i++) {
02987 cpl_table *dummy;
02988 cpl_vector *x;
02989 cpl_vector *y;
02990 cpl_bivector *z;
02991 cpl_vector *c;
02992 cpl_polynomial *p;
02993 cpl_vector *point;
02994 double *dpoint;
02995 int npoints;
02996
02997 if (!cpl_table_has_column(idscoeff, clab[i]))
02998 break;
02999
03000 npoints = nrow - cpl_table_count_invalid(idscoeff, clab[i]);
03001 if (npoints < 18)
03002 break;
03003
03004 dummy = cpl_table_new(nrow);
03005 cpl_table_duplicate_column(dummy, "x", idscoeff, "x");
03006 cpl_table_duplicate_column(dummy, "y", idscoeff, "y");
03007 cpl_table_duplicate_column(dummy, clab[i], idscoeff, clab[i]);
03008 cpl_table_erase_invalid(dummy);
03009
03010 x = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy, "x"));
03011 y = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy, "y"));
03012 z = cpl_bivector_wrap_vectors(x, y);
03013 c = cpl_vector_wrap(npoints, cpl_table_get_data_double(dummy,
03014 clab[i]));
03015 p = cpl_polynomial_fit_2d_create(z, c, 2, NULL);
03016 cpl_bivector_unwrap_vectors(z);
03017 cpl_vector_unwrap(x);
03018 cpl_vector_unwrap(y);
03019 cpl_vector_unwrap(c);
03020 cpl_table_delete(dummy);
03021
03022 point = cpl_vector_new(2);
03023 dpoint = cpl_vector_get_data(point);
03024 for (j = 0; j < nrow; j++) {
03025 dpoint[0] = cpl_table_get_double(idscoeff, "x", j, NULL);
03026 dpoint[1] = cpl_table_get_double(idscoeff, "y", j, NULL);
03027 cpl_table_set_double(idscoeff, clab[i], j,
03028 cpl_polynomial_eval(p, point));
03029 }
03030 cpl_vector_delete(point);
03031 cpl_polynomial_delete(p);
03032 }
03033 }
03034
03035 return CPL_ERROR_NONE;
03036 }
03037
03038
03064 cpl_error_code mos_interpolate_wavecalib(cpl_table *idscoeff,
03065 cpl_image *wavemap, int mode,
03066 int degree)
03067 {
03068 const char *func = "mos_interpolate_wavecalib";
03069
03070 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
03071
03072
03073 cpl_vector *wave;
03074 cpl_vector *positions;
03075 cpl_polynomial *trend;
03076
03077 float *p;
03078 float *data;
03079 double *wdata;
03080 double *pdata;
03081
03082 double c;
03083 double mse, ksigma;
03084
03085 int order;
03086 int nrows, first_row, last_row;
03087 int nx, ny;
03088 int npoints, rpoints;
03089 int null;
03090 int i, j, k;
03091
03092 int polyorder = 4;
03093
03094
03095 if (idscoeff == NULL)
03096 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03097
03098 if (mode < 0 || mode > 2)
03099 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
03100
03101 if (mode == 0 || degree < 0)
03102 return CPL_ERROR_NONE;
03103
03104 if (wavemap) {
03105
03106
03107
03108
03109
03110 cpl_image_turn(wavemap, -1);
03111
03112 nx = cpl_image_get_size_x(wavemap);
03113 ny = cpl_image_get_size_y(wavemap);
03114 data = cpl_image_get_data(wavemap);
03115
03116 for (i = 0; i < ny; i++) {
03117
03118
03119
03120
03121
03122
03123 npoints = 0;
03124 p = data + i*nx;
03125 for (j = 0; j < nx; j++)
03126 if (p[j] > 1.0)
03127 npoints++;
03128
03129 if (npoints > polyorder + 1) {
03130
03131
03132
03133
03134
03135 wave = cpl_vector_new(npoints);
03136 wdata = cpl_vector_get_data(wave);
03137 positions = cpl_vector_new(npoints);
03138 pdata = cpl_vector_get_data(positions);
03139
03140 npoints = 0;
03141 p = data + i*nx;
03142 for (j = 0; j < nx; j++) {
03143 if (p[j] > 1.0) {
03144 wdata[npoints] = p[j];
03145 pdata[npoints] = j;
03146 npoints++;
03147 }
03148 }
03149
03150 trend = cpl_polynomial_fit_1d_create(positions, wave,
03151 polyorder, &mse);
03152
03153 ksigma = 3*sqrt(mse);
03154
03155 cpl_vector_delete(wave);
03156 cpl_vector_delete(positions);
03157
03158 if (trend) {
03159
03160
03161
03162
03163
03164 rpoints = 0;
03165 p = data + i*nx;
03166 for (j = 0; j < nx; j++)
03167 if (p[j] > 1.0)
03168 if (fabs(cpl_polynomial_eval_1d(trend, j, NULL)
03169 - p[j]) < ksigma)
03170 rpoints++;
03171
03172 if (rpoints < npoints && rpoints > polyorder + 1) {
03173
03174 wave = cpl_vector_new(rpoints);
03175 wdata = cpl_vector_get_data(wave);
03176 positions = cpl_vector_new(rpoints);
03177 pdata = cpl_vector_get_data(positions);
03178
03179 npoints = 0;
03180 p = data + i*nx;
03181 for (j = 0; j < nx; j++) {
03182 if (p[j] > 1.0) {
03183 if (fabs(cpl_polynomial_eval_1d(trend,
03184 j, NULL) - p[j])
03185 < ksigma) {
03186 wdata[npoints] = p[j];
03187 pdata[npoints] = j;
03188 npoints++;
03189 }
03190 }
03191 }
03192
03193 cpl_polynomial_delete(trend);
03194 trend = cpl_polynomial_fit_1d_create(positions, wave,
03195 polyorder, NULL);
03196
03197 cpl_vector_delete(wave);
03198 cpl_vector_delete(positions);
03199 }
03200 }
03201
03202 if (trend) {
03203 p = data + i*nx;
03204 if (mode == 1) {
03205 for (j = 0; j < nx; j++)
03206 if (p[j] < 1.0)
03207 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
03208 }
03209 else if (mode == 2) {
03210 for (j = 0; j < nx; j++)
03211 p[j] = cpl_polynomial_eval_1d(trend, j, NULL);
03212 }
03213 cpl_polynomial_delete(trend);
03214 }
03215 else {
03216 cpl_msg_warning(func,
03217 "Invalid wavelength field fit (ignored)");
03218 }
03219 }
03220
03221 }
03222
03223 cpl_image_turn(wavemap, 1);
03224
03225 }
03226
03227
03228
03229
03230
03231
03232 nrows = cpl_table_get_nrow(idscoeff);
03233
03234 order = 0;
03235 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
03236 ++order;
03237 --order;
03238
03239 if (degree == 0) {
03240 for (k = 0; k <= order; k++) {
03241 double m;
03242 if (cpl_table_has_column(idscoeff, clab[k])) {
03243 m = cpl_table_get_column_median(idscoeff, clab[k]);
03244 cpl_table_fill_column_window_double(idscoeff, clab[k],
03245 0, nrows, m);
03246 }
03247 }
03248
03249 return CPL_ERROR_NONE;
03250 }
03251
03252 first_row = 0;
03253 while (!cpl_table_is_valid(idscoeff, clab[0], first_row))
03254 first_row++;
03255
03256 last_row = nrows - 1;
03257 while (!cpl_table_is_valid(idscoeff, clab[0], last_row))
03258 last_row--;
03259
03260 for (k = 0; k <= order; k++) {
03261
03262 npoints = nrows - cpl_table_count_invalid(idscoeff, clab[k]);
03263 wave = cpl_vector_new(npoints);
03264 wdata = cpl_vector_get_data(wave);
03265 positions = cpl_vector_new(npoints);
03266 pdata = cpl_vector_get_data(positions);
03267
03268 npoints = 0;
03269 for (i = first_row; i <= last_row; i++) {
03270 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
03271 if (null == 0) {
03272 wdata[npoints] = c;
03273 pdata[npoints] = i;
03274 npoints++;
03275 }
03276 }
03277
03278
03279
03280
03281 if (degree == 1) {
03282 cpl_vector *p;
03283 cpl_vector *w;
03284 cpl_bivector *list;
03285 double q, m;
03286
03287 if (npoints > 4) {
03288 p = cpl_vector_extract(positions, 2, npoints - 2, 1);
03289 w = cpl_vector_extract(wave, 2, npoints - 2, 1);
03290 }
03291 else {
03292 p = positions;
03293 w = wave;
03294 }
03295
03296 list = cpl_bivector_wrap_vectors(p, w);
03297
03298 robustLinearFit(list, &q, &m, &mse);
03299 cpl_bivector_unwrap_vectors(list);
03300 for (i = first_row; i <= last_row; i++)
03301 cpl_table_set_double(idscoeff, clab[k], i, q + m*i);
03302
03303 if (npoints > 4) {
03304 cpl_vector_delete(p);
03305 cpl_vector_delete(w);
03306 }
03307
03308 cpl_vector_delete(wave);
03309 cpl_vector_delete(positions);
03310
03311 continue;
03312 }
03313
03314
03315
03316 trend = cpl_polynomial_fit_1d_create(positions, wave, degree, &mse);
03317
03318 ksigma = 3*sqrt(mse);
03319
03320 cpl_vector_delete(wave);
03321 cpl_vector_delete(positions);
03322
03323
03324
03325
03326
03327 if (trend) {
03328 rpoints = 0;
03329 for (i = first_row; i <= last_row; i++) {
03330 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
03331 if (null == 0) {
03332 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
03333 < ksigma) {
03334 rpoints++;
03335 }
03336 }
03337 }
03338
03339 if (rpoints > 0 && rpoints < npoints) {
03340 cpl_msg_debug(func, "%d points rejected from "
03341 "wavelength calibration fit",
03342 npoints - rpoints);
03343
03344 wave = cpl_vector_new(rpoints);
03345 wdata = cpl_vector_get_data(wave);
03346 positions = cpl_vector_new(rpoints);
03347 pdata = cpl_vector_get_data(positions);
03348
03349 npoints = 0;
03350 for (i = first_row; i <= last_row; i++) {
03351 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
03352 if (null == 0) {
03353 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
03354 < ksigma) {
03355 wdata[npoints] = c;
03356 pdata[npoints] = i;
03357 npoints++;
03358 }
03359 }
03360 }
03361
03362 if (npoints) {
03363 cpl_polynomial_delete(trend);
03364 trend = cpl_polynomial_fit_1d_create(positions,
03365 wave, degree, NULL);
03366 }
03367
03368 cpl_vector_delete(wave);
03369 cpl_vector_delete(positions);
03370
03371 }
03372 }
03373
03374 if (trend) {
03375 for (i = first_row; i <= last_row; i++) {
03376 if (mode == 1) {
03377 if (!cpl_table_is_valid(idscoeff, clab[k], i)) {
03378 cpl_table_set_double(idscoeff, clab[k], i,
03379 cpl_polynomial_eval_1d(trend, i,
03380 NULL));
03381 }
03382 }
03383 else if (mode == 2) {
03384 cpl_table_set_double(idscoeff, clab[k], i,
03385 cpl_polynomial_eval_1d(trend, i, NULL));
03386 }
03387 }
03388 cpl_polynomial_delete(trend);
03389 }
03390 else {
03391 cpl_msg_warning(func, "Invalid IDS coefficient fit (ignored)");
03392 }
03393
03394 }
03395
03396 return CPL_ERROR_NONE;
03397 }
03398
03416 cpl_error_code mos_interpolate_wavecalib_mos(cpl_table *idscoeff,
03417 int mode,
03418 int degree)
03419 {
03420 const char *func = "mos_interpolate_wavecalib";
03421
03422 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
03423
03424
03425 cpl_vector *wave;
03426 cpl_vector *positions;
03427 cpl_polynomial *trend;
03428
03429 double *wdata;
03430 double *pdata;
03431
03432 double c;
03433 double mse, ksigma;
03434
03435 int order;
03436 int nrows, first_row, last_row;
03437 int npoints, rpoints;
03438 int null;
03439 int i;
03440
03441
03442 if (idscoeff == NULL)
03443 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03444
03445 if (mode < 0 || mode > 2)
03446 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
03447
03448 if (mode == 0 || degree < 0)
03449 return CPL_ERROR_NONE;
03450
03451
03452
03453
03454
03455 nrows = cpl_table_get_nrow(idscoeff);
03456
03457 order = 0;
03458 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
03459 ++order;
03460 --order;
03461
03462
03463
03464 int kinit = 1;
03465 if (degree == 0)
03466 kinit = 0;
03467 for (int k = kinit; k <= order; k++) {
03468 double m;
03469 if (cpl_table_has_column(idscoeff, clab[k])) {
03470 m = cpl_table_get_column_median(idscoeff, clab[k]);
03471 cpl_table_fill_column_window_double(idscoeff, clab[k],
03472 0, nrows, m);
03473 }
03474 }
03475
03476 if(degree > 0)
03477 {
03478 first_row = 0;
03479 while (!cpl_table_is_valid(idscoeff, clab[0], first_row))
03480 first_row++;
03481
03482 last_row = nrows - 1;
03483 while (!cpl_table_is_valid(idscoeff, clab[0], last_row))
03484 last_row--;
03485
03486 int korder = 0;
03487
03488 npoints = nrows - cpl_table_count_invalid(idscoeff, clab[korder]);
03489 wave = cpl_vector_new(npoints);
03490 wdata = cpl_vector_get_data(wave);
03491 positions = cpl_vector_new(npoints);
03492 pdata = cpl_vector_get_data(positions);
03493
03494 npoints = 0;
03495 for (i = first_row; i <= last_row; i++) {
03496 c = cpl_table_get_double(idscoeff, clab[korder], i, &null);
03497 if (null == 0) {
03498 wdata[npoints] = c;
03499 pdata[npoints] = i;
03500 npoints++;
03501 }
03502 }
03503
03504
03505
03506
03507 if (degree == 1) {
03508 cpl_vector *p;
03509 cpl_vector *w;
03510 cpl_bivector *list;
03511 double q, m;
03512
03513 if (npoints > 4) {
03514 p = cpl_vector_extract(positions, 2, npoints - 2, 1);
03515 w = cpl_vector_extract(wave, 2, npoints - 2, 1);
03516 }
03517 else {
03518 p = positions;
03519 w = wave;
03520 }
03521
03522 list = cpl_bivector_wrap_vectors(p, w);
03523
03524 robustLinearFit(list, &q, &m, &mse);
03525 cpl_bivector_unwrap_vectors(list);
03526 for (i = first_row; i <= last_row; i++)
03527 cpl_table_set_double(idscoeff, clab[korder], i, q + m*i);
03528
03529 if (npoints > 4) {
03530 cpl_vector_delete(p);
03531 cpl_vector_delete(w);
03532 }
03533
03534 cpl_vector_delete(wave);
03535 cpl_vector_delete(positions);
03536
03537 }
03538 else
03539 {
03540
03541
03542
03543 trend = cpl_polynomial_fit_1d_create(positions, wave, degree, &mse);
03544
03545 ksigma = 3*sqrt(mse);
03546
03547 cpl_vector_delete(wave);
03548 cpl_vector_delete(positions);
03549
03550
03551
03552
03553
03554 if (trend) {
03555 rpoints = 0;
03556 for (i = first_row; i <= last_row; i++) {
03557 c = cpl_table_get_double(idscoeff, clab[korder], i, &null);
03558 if (null == 0) {
03559 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
03560 < ksigma) {
03561 rpoints++;
03562 }
03563 }
03564 }
03565
03566 if (rpoints > 0 && rpoints < npoints) {
03567 cpl_msg_debug(func, "%d points rejected from "
03568 "wavelength calibration fit",
03569 npoints - rpoints);
03570
03571 wave = cpl_vector_new(rpoints);
03572 wdata = cpl_vector_get_data(wave);
03573 positions = cpl_vector_new(rpoints);
03574 pdata = cpl_vector_get_data(positions);
03575
03576 npoints = 0;
03577 for (i = first_row; i <= last_row; i++) {
03578 c = cpl_table_get_double(idscoeff, clab[korder], i, &null);
03579 if (null == 0) {
03580 if (fabs(cpl_polynomial_eval_1d(trend, i, NULL) - c)
03581 < ksigma) {
03582 wdata[npoints] = c;
03583 pdata[npoints] = i;
03584 npoints++;
03585 }
03586 }
03587 }
03588
03589 if (npoints) {
03590 cpl_polynomial_delete(trend);
03591 trend = cpl_polynomial_fit_1d_create(positions,
03592 wave, degree, NULL);
03593 }
03594
03595 cpl_vector_delete(wave);
03596 cpl_vector_delete(positions);
03597
03598 }
03599 }
03600
03601 if (trend) {
03602 for (i = first_row; i <= last_row; i++) {
03603 if (mode == 1) {
03604 if (!cpl_table_is_valid(idscoeff, clab[korder], i)) {
03605 cpl_table_set_double(idscoeff, clab[korder], i,
03606 cpl_polynomial_eval_1d(trend, i,
03607 NULL));
03608 }
03609 }
03610 else if (mode == 2) {
03611 cpl_table_set_double(idscoeff, clab[korder], i,
03612 cpl_polynomial_eval_1d(trend, i, NULL));
03613 }
03614 }
03615 cpl_polynomial_delete(trend);
03616 }
03617 else {
03618 cpl_msg_warning(func, "Invalid IDS coefficient fit (ignored)");
03619 }
03620 }
03621 }
03622
03623 return CPL_ERROR_NONE;
03624 }
03625
03626
03651
03652
03653
03654 cpl_image *mos_remove_bias(cpl_image *image, cpl_image *bias,
03655 cpl_table *overscans)
03656 {
03657 const char *func = "mos_remove_bias";
03658
03659 cpl_image *unbiased;
03660 cpl_image *overscan;
03661 double mean_bias_level;
03662 double mean_overscans_level;
03663 int count;
03664 int nrows;
03665 int xlow, ylow, xhig, yhig;
03666 int i;
03667
03668
03669 if (image == NULL || overscans == NULL) {
03670 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03671 return NULL;
03672 }
03673
03674 nrows = cpl_table_get_nrow(overscans);
03675
03676 if (nrows == 0) {
03677 cpl_msg_error(func, "Empty overscan table");
03678 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
03679 return NULL;
03680 }
03681
03682 if (bias) {
03683 if (nrows == 1) {
03684 unbiased = cpl_image_subtract_create(image, bias);
03685 if (unbiased == NULL) {
03686 cpl_msg_error(func, "Incompatible master bias");
03687 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03688 }
03689 return unbiased;
03690 }
03691 mean_bias_level = cpl_image_get_mean(bias);
03692 }
03693 else {
03694 if (nrows == 1) {
03695 cpl_msg_error(func, "No master bias in input, and no overscan "
03696 "regions in input image: bias subtraction "
03697 "cannot be performed!");
03698 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
03699 return NULL;
03700 }
03701 mean_bias_level = 0.0;
03702 }
03703
03704 mean_overscans_level = 0.0;
03705 count = 0;
03706 for (i = 0; i < nrows; i++) {
03707 xlow = cpl_table_get_int(overscans, "xlow", i, NULL);
03708 ylow = cpl_table_get_int(overscans, "ylow", i, NULL);
03709 xhig = cpl_table_get_int(overscans, "xhig", i, NULL);
03710 yhig = cpl_table_get_int(overscans, "yhig", i, NULL);
03711
03712 if (i == 0) {
03713 unbiased = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
03714 if (unbiased == NULL) {
03715 cpl_msg_error(func, "Incompatible overscan table");
03716 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03717 return NULL;
03718 }
03719 if (bias) {
03720 if (cpl_image_subtract(unbiased, bias)) {
03721 cpl_msg_error(func, "Incompatible master bias");
03722 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03723 cpl_image_delete(unbiased);
03724 return NULL;
03725 }
03726 }
03727 }
03728 else {
03729 overscan = cpl_image_extract(image, xlow+1, ylow+1, xhig, yhig);
03730 if (overscan == NULL) {
03731 cpl_msg_error(func, "Incompatible overscan table");
03732 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
03733 cpl_image_delete(unbiased);
03734 return NULL;
03735 }
03736
03737 mean_overscans_level += cpl_image_get_median(overscan);
03738 count++;
03739
03740
03741
03742
03743
03744
03745
03746
03747 cpl_image_delete(overscan);
03748 }
03749 }
03750
03751
03752
03753
03754
03755 mean_overscans_level /= count;
03756
03757 cpl_image_subtract_scalar(unbiased, mean_overscans_level - mean_bias_level);
03758
03759 cpl_msg_info(cpl_func,
03760 "Difference between mean overscans level "
03761 "and mean bias level: %.2f",
03762 mean_overscans_level - mean_bias_level);
03763
03764 return unbiased;
03765
03766 }
03767
03768
03827 cpl_error_code mos_arc_background_1D(float *spectrum, float *back,
03828 int length, int msize, int fsize)
03829 {
03830 const char *func = "mos_arc_background_1D";
03831
03832 float *minf;
03833 float *maxf;
03834 float *smof;
03835 int i;
03836
03837
03838 if (spectrum == NULL || back == NULL)
03839 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03840
03841 if (msize % 2 == 0)
03842 msize++;
03843
03844 if (fsize % 2 == 0)
03845 fsize++;
03846
03847 if (msize < 3 || fsize < msize || length < 2*fsize)
03848 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
03849
03850
03851 minf = min_filter(spectrum, length, msize);
03852 smof = smo_filter(minf, length, fsize);
03853 cpl_free(minf);
03854 maxf = max_filter(smof, length, 2*msize+1);
03855 cpl_free(smof);
03856 smof = smo_filter(maxf, length, 2*fsize+1);
03857 cpl_free(maxf);
03858 minf = min_filter(smof, length, 2*msize+1);
03859 cpl_free(smof);
03860 smof = smo_filter(minf, length, 2*fsize+1);
03861 cpl_free(minf);
03862
03863 for (i = 0; i < length; i++)
03864 back[i] = smof[i];
03865
03866 cpl_free(smof);
03867
03868 return CPL_ERROR_NONE;
03869
03870 }
03871
03872
03929 cpl_image *mos_arc_background(cpl_image *image, int msize, int fsize)
03930 {
03931 const char *func = "mos_arc_background";
03932
03933 cpl_image *fimage;
03934 cpl_image *bimage;
03935 float *data;
03936 float *bdata;
03937 float *row;
03938 float *brow;
03939 int nx, ny;
03940 int i;
03941
03942
03943 if (image == NULL) {
03944 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
03945 return NULL;
03946 }
03947
03948 if (msize % 2 == 0)
03949 msize++;
03950
03951 if (fsize % 2 == 0)
03952 fsize++;
03953
03954 nx = cpl_image_get_size_x(image);
03955 ny = cpl_image_get_size_y(image);
03956
03957 bimage = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
03958
03959 fimage = mos_image_filter_median(image, 3, 3);
03960
03961 data = cpl_image_get_data_float(fimage);
03962 bdata = cpl_image_get_data_float(bimage);
03963
03964 for (i = 0; i < ny; i++) {
03965 row = data + i * nx;
03966 brow = bdata + i * nx;
03967 if (mos_arc_background_1D(row, brow, nx, msize, fsize)) {
03968 cpl_error_set_where(func);
03969 cpl_image_delete(fimage);
03970 cpl_image_delete(bimage);
03971 return NULL;
03972 }
03973 }
03974
03975 cpl_image_delete(fimage);
03976
03977 return bimage;
03978 }
03979
03980
04001 int mos_lines_width(const float *spectrum, int length)
04002 {
04003
04004 const char *func = "mos_lines_width";
04005
04006 double *profile1 = cpl_calloc(length - 1, sizeof(double));
04007 double *profile2 = cpl_calloc(length - 1, sizeof(double));
04008
04009 double norm, value, max;
04010 int radius = 20;
04011 int short_length = length - 2*radius - 1;
04012 int width;
04013 int i, j, k;
04014
04015
04016
04017
04018
04019
04020 for (j = 0, i = 1; i < length; j++, i++) {
04021 profile1[j] = profile2[j] = spectrum[i] - spectrum[j];
04022 if (profile1[j] < 0)
04023 profile1[j] = 0;
04024 if (profile2[j] > 0)
04025 profile2[j] = 0;
04026 else
04027 profile2[j] = -profile2[j];
04028 }
04029
04030
04031
04032
04033
04034
04035 length--;
04036
04037 norm = 0;
04038 for (i = 0; i < length; i++)
04039 if (norm < profile1[i])
04040 norm = profile1[i];
04041
04042 for (i = 0; i < length; i++) {
04043 profile1[i] /= norm;
04044 profile2[i] /= norm;
04045 }
04046
04047
04048
04049
04050
04051
04052 max = -1;
04053 for (i = 0; i <= radius; i++) {
04054 value = 0;
04055 for (j = 0; j < short_length; j++) {
04056 k = radius+j;
04057 value += profile1[k] * profile2[k+i];
04058 }
04059 if (max < value) {
04060 max = value;
04061 width = i;
04062 }
04063 }
04064
04065 cpl_free(profile1);
04066 cpl_free(profile2);
04067
04068 if (max < 0.0) {
04069 cpl_msg_debug(func, "Cannot estimate line width");
04070 width = 1;
04071 }
04072
04073 return width;
04074
04075 }
04076
04077
04104 cpl_vector *mos_peak_candidates(const float *spectrum,
04105 int length, float level,
04106 float exp_width)
04107 {
04108
04109 const char *func = "mos_peak_candidates";
04110
04111 int i, j;
04112 int nint = length - 1;
04113 int n = 0;
04114 int width = 2 * ceil(exp_width / 2) + 1;
04115 int start = width / 2;
04116 int end = length - width / 2;
04117 int step;
04118 float *smo;
04119 double *data = cpl_calloc(length/2, sizeof(double));
04120
04121
04122 if (spectrum == NULL) {
04123 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
04124 return NULL;
04125 }
04126
04127
04128
04129
04130
04131
04132
04133 if (width > 7) {
04134 smo = cpl_calloc(length, sizeof(float));
04135 start = width / 2;
04136 end = length - width / 2;
04137 for (i = 0; i < start; i++)
04138 smo[i] = spectrum[i];
04139 for (i = start; i < end; i++) {
04140 for (j = i - start; j <= i + start; j++)
04141 smo[i] += spectrum[j];
04142 smo[i] /= width;
04143 }
04144 for (i = end; i < length; i++)
04145 smo[i] = spectrum[i];
04146 }
04147 else {
04148 smo = (float *)spectrum;
04149 }
04150
04151
04152
04153
04154
04155
04156 if (width > 20)
04157 step = width / 2;
04158 else
04159 step = 1;
04160
04161 for (i = step; i < nint - step + 1; i += step) {
04162 if (smo[i] > level) {
04163 if (smo[i] >= smo[i-step] && smo[i] > smo[i+step]) {
04164 if (smo[i-step] != 0.0 && smo[i+step] != 0.0) {
04165 data[n] = i + step * values_to_dx(smo[i-step], smo[i], smo[i+step]);
04166 ++n;
04167 }
04168 }
04169 }
04170 }
04171
04172 if (width > 7) {
04173 cpl_free(smo);
04174 }
04175
04176 if (n == 0) {
04177 cpl_free(data);
04178 return NULL;
04179 }
04180
04181 return cpl_vector_wrap(n, data);
04182
04183 }
04184
04185
04207 cpl_vector *mos_refine_peaks(const float *spectrum, int length,
04208 cpl_vector *peaks, int sradius)
04209 {
04210
04211 const char *func = "mos_refine_peaks";
04212
04213 double *data;
04214 float pos;
04215 int npeaks;
04216 int startPos, endPos;
04217 int window = 2*sradius+1;
04218 int i, j;
04219
04220
04221 if (peaks == NULL || spectrum == NULL) {
04222 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
04223 return NULL;
04224 }
04225
04226 npeaks = cpl_vector_get_size(peaks);
04227 data = cpl_vector_unwrap(peaks);
04228
04229 for (i = 0; i < npeaks; i++) {
04230 startPos = data[i] - window/2;
04231 endPos = startPos + window;
04232 if (startPos < 0 || endPos >= length)
04233 continue;
04234
04235 if (0 == peakPosition(spectrum + startPos, window, &pos, 1)) {
04236 pos += startPos;
04237 data[i] = pos;
04238 }
04239 }
04240
04241 for (i = 1; i < npeaks; i++)
04242 if (data[i] - data[i-1] < 0.5)
04243 data[i-1] = -1.0;
04244
04245 for (i = 0, j = 0; i < npeaks; i++) {
04246 if (data[i] > 0.0) {
04247 if (i != j)
04248 data[j] = data[i];
04249 j++;
04250 }
04251 }
04252
04253 return cpl_vector_wrap(j, data);
04254
04255 }
04256
04257
04258 void mos_set_multiplex(int multiplex)
04259 {
04260 mos_multiplex = multiplex;
04261 }
04262
04316 cpl_bivector *mos_identify_peaks(cpl_vector *peaks, cpl_vector *lines,
04317 double min_disp, double max_disp,
04318 double tolerance)
04319 {
04320
04321 int i, j, k, l;
04322 int nlint, npint;
04323 int minpos;
04324 float min;
04325 double lratio, pratio;
04326 double lo_start, lo_end, hi_start, hi_end, denom;
04327 double disp, variation, prev_variation;
04328 int max, maxpos, minl, mink;
04329 int ambiguous;
04330 int npeaks_lo, npeaks_hi;
04331 int *peak_lo;
04332 int *peak_hi;
04333 int **ident;
04334 int *nident;
04335 int *lident;
04336
04337 double *peak;
04338 double *line;
04339 int npeaks, nlines;
04340
04341 double *xpos;
04342 double *lambda;
04343 int *ilambda;
04344 double *tmp_xpos;
04345 double *tmp_lambda;
04346 int *tmp_ilambda;
04347 int *flag;
04348 int n = 0;
04349 int nn;
04350 int nseq = 0;
04351 int gap;
04352 int *seq_length;
04353 int found;
04354
04355 peak = cpl_vector_get_data(peaks);
04356 npeaks = cpl_vector_get_size(peaks);
04357 line = cpl_vector_get_data(lines);
04358 nlines = cpl_vector_get_size(lines);
04359
04360 if (npeaks < 4)
04361 return NULL;
04362
04363 peak_lo = cpl_malloc(npeaks * sizeof(int));
04364 peak_hi = cpl_malloc(npeaks * sizeof(int));
04365 nident = cpl_calloc(npeaks, sizeof(int));
04366 lident = cpl_calloc(nlines, sizeof(int));
04367 xpos = cpl_calloc(npeaks, sizeof(double));
04368 lambda = cpl_calloc(npeaks, sizeof(double));
04369 ilambda = cpl_calloc(npeaks, sizeof(int));
04370 tmp_xpos = cpl_calloc(npeaks, sizeof(double));
04371 tmp_lambda = cpl_calloc(npeaks, sizeof(double));
04372 tmp_ilambda = cpl_calloc(npeaks, sizeof(int));
04373 flag = cpl_calloc(npeaks, sizeof(int));
04374 seq_length = cpl_calloc(npeaks, sizeof(int));
04375 ident = cpl_malloc(npeaks * sizeof(int *));
04376 for (i = 0; i < npeaks; i++)
04377 ident[i] = cpl_malloc(3 * npeaks * sizeof(int));
04378
04379
04380
04381
04382
04383
04384 nlint = nlines - 1;
04385 npint = npeaks - 1;
04386
04387
04388
04389
04390
04391
04392 for (i = 1; i < nlint; i++) {
04393
04394
04395
04396
04397
04398
04399
04400
04401
04402 lratio = (line[i+1] - line[i]) / (line[i] - line[i-1]);
04403
04404
04405
04406
04407
04408
04409 for (j = 1; j < npint; j++) {
04410
04411
04412
04413
04414
04415
04416
04417
04418
04419
04420
04421
04422 lo_start = peak[j] - (line[i] - line[i-1]) / min_disp;
04423 lo_end = peak[j] - (line[i] - line[i-1]) / max_disp;
04424 hi_start = peak[j] + (line[i+1] - line[i]) / max_disp;
04425 hi_end = peak[j] + (line[i+1] - line[i]) / min_disp;
04426
04427 for (npeaks_lo = 0, k = 0; k < npeaks; k++) {
04428 if (peak[k] > lo_end)
04429 break;
04430 if (peak[k] > lo_start) {
04431 peak_lo[npeaks_lo] = k;
04432 ++npeaks_lo;
04433 }
04434 }
04435
04436 if (npeaks_lo == 0)
04437 continue;
04438
04439 for (npeaks_hi = 0, k = 0; k < npeaks; k++) {
04440 if (peak[k] > hi_end)
04441 break;
04442 if (peak[k] > hi_start) {
04443 peak_hi[npeaks_hi] = k;
04444 ++npeaks_hi;
04445 }
04446 }
04447
04448 if (npeaks_hi == 0)
04449 continue;
04450
04451
04452
04453
04454
04455
04456
04457
04458
04459
04460 prev_variation = 1000.0;
04461 minl = mink = 0;
04462
04463 for (k = 0; k < npeaks_lo; k++) {
04464 denom = peak[j] - peak[peak_lo[k]];
04465 for (l = 0; l < npeaks_hi; l++) {
04466
04467
04468
04469
04470
04471
04472
04473 pratio = (peak[peak_hi[l]] - peak[j]) / denom;
04474
04475
04476
04477
04478
04479
04480
04481
04482
04483
04484
04485
04486 variation = fabs(lratio-pratio) / pratio;
04487
04488 if (variation < tolerance) {
04489 if (variation < prev_variation) {
04490 prev_variation = variation;
04491 minl = l;
04492 mink = k;
04493 }
04494 }
04495 }
04496 }
04497 if (prev_variation < tolerance) {
04498 ident[j][nident[j]] = i;
04499 ident[peak_hi[minl]][nident[peak_hi[minl]]] = i + 1;
04500 ident[peak_lo[mink]][nident[peak_lo[mink]]] = i - 1;
04501 ++nident[j];
04502 ++nident[peak_hi[minl]];
04503 ++nident[peak_lo[mink]];
04504 }
04505 }
04506 }
04507
04508
04509
04510
04511
04512
04513
04514
04515 for (i = 0; i < npeaks; i++) {
04516
04517
04518
04519
04520
04521
04522
04523
04524 if (nident[i] > 1) {
04525
04526
04527
04528
04529
04530
04531 for (j = 0; j < nlines; j++)
04532 lident[j] = 0;
04533
04534
04535
04536
04537
04538
04539
04540 for (j = 0; j < nident[i]; j++)
04541 ++lident[ident[i][j]];
04542
04543
04544
04545
04546
04547
04548 max = 0;
04549 maxpos = 0;
04550 for (j = 0; j < nlines; j++) {
04551 if (max < lident[j]) {
04552 max = lident[j];
04553 maxpos = j;
04554 }
04555 }
04556
04557
04558
04559
04560
04561
04562
04563
04564 ambiguous = 0;
04565
04566 for (k = maxpos + 1; k < nlines; k++) {
04567 if (lident[k] == max) {
04568 ambiguous = 1;
04569 break;
04570 }
04571 }
04572
04573 if (ambiguous)
04574 continue;
04575
04576
04577
04578
04579
04580
04581
04582 tmp_xpos[n] = peak[i];
04583 tmp_lambda[n] = line[maxpos];
04584 tmp_ilambda[n] = maxpos;
04585
04586 ++n;
04587
04588 }
04589
04590 }
04591
04592
04593
04594
04595
04596
04597
04598
04599
04600
04601
04602
04603
04604
04605 if (n > 1) {
04606 nn = 0;
04607 nseq = 0;
04608 for (k = 0; k < n; k++) {
04609 if (flag[k] == 0) {
04610 flag[k] = 1;
04611 xpos[nn] = tmp_xpos[k];
04612 lambda[nn] = tmp_lambda[k];
04613 ilambda[nn] = tmp_ilambda[k];
04614 ++seq_length[nseq];
04615 ++nn;
04616
04617
04618
04619
04620
04621
04622
04623 i = k;
04624 while (i < n - 1) {
04625 found = 0;
04626 for (j = i + 1; j < n; j++) {
04627 if (flag[j] == 0) {
04628 disp = (tmp_lambda[j] - tmp_lambda[i])
04629 / (tmp_xpos[j] - tmp_xpos[i]);
04630 if (disp >= min_disp && disp <= max_disp) {
04631 flag[j] = 1;
04632 xpos[nn] = tmp_xpos[j];
04633 lambda[nn] = tmp_lambda[j];
04634 ilambda[nn] = tmp_ilambda[j];
04635 ++seq_length[nseq];
04636 ++nn;
04637 i = j;
04638 found = 1;
04639 break;
04640 }
04641 }
04642 }
04643 if (!found)
04644 break;
04645 }
04646
04647
04648
04649
04650
04651
04652 ++nseq;
04653 k = 0;
04654 }
04655 }
04656
04657
04658
04659
04660
04661
04662 maxpos = max = 0;
04663
04664 if (mos_multiplex < 0) {
04665 for (i = 0; i < nseq; i++) {
04666 if (seq_length[i] > max) {
04667 max = seq_length[i];
04668 maxpos = i;
04669 }
04670 }
04671 }
04672 else {
04673
04674
04675
04676
04677
04678
04679
04680 nn = 0;
04681 found = 0;
04682
04683 for (i = 0; i < nseq; i++) {
04684 n = seq_length[i];
04685 if (n > 5) {
04686 cpl_array *regions = cpl_array_new(n, CPL_TYPE_INT);
04687 int region;
04688
04689 for (j = 0; j < n; j++)
04690 cpl_array_set_int(regions, j,
04691 ((int)floor(xpos[nn + j])) / mos_region_size);
04692
04693 region = (int)cpl_array_get_median(regions);
04694 cpl_array_delete(regions);
04695
04696 if (mos_multiplex == region) {
04697 if (found) {
04698 cpl_msg_debug(cpl_func, "More than one spectrum found in "
04699 "region %d (only the first one is extracted)",
04700 mos_multiplex);
04701 break;
04702 }
04703 found = 1;
04704 max = seq_length[i];
04705 maxpos = i;
04706 }
04707 }
04708 nn += seq_length[i];
04709 }
04710 }
04711
04712
04713
04714
04715
04716
04717 nn = 0;
04718 for (i = 0; i < maxpos; i++)
04719 nn += seq_length[i];
04720
04721
04722
04723
04724
04725 n = max;
04726 for (i = 0; i < n; i++, nn++) {
04727 xpos[i] = xpos[nn];
04728 lambda[i] = lambda[nn];
04729 ilambda[i] = ilambda[nn];
04730 }
04731
04732
04733
04734
04735
04736
04737 for (i = 1; i < n; i++) {
04738 gap = ilambda[i] - ilambda[i-1];
04739 for (j = 1; j < gap; j++) {
04740
04741 if (j == 1) {
04742
04743
04744
04745
04746
04747 disp = (lambda[i] - lambda[i-1]) / (xpos[i] - xpos[i-1]);
04748 }
04749
04750
04751
04752
04753
04754
04755 hi_start = xpos[i-1] + (line[ilambda[i-1] + j] - lambda[i-1]) / disp;
04756
04757
04758
04759
04760
04761
04762
04763
04764
04765
04766
04767
04768
04769 found = 0;
04770 for (k = 0; k < npeaks; k++) {
04771 if (fabs(peak[k] - hi_start) < 2) {
04772 for (l = n; l > i; l--) {
04773 xpos[l] = xpos[l-1];
04774 lambda[l] = lambda[l-1];
04775 ilambda[l] = ilambda[l-1];
04776 }
04777 xpos[i] = peak[k];
04778 lambda[i] = line[ilambda[i-1] + j];
04779 ilambda[i] = ilambda[i-1] + j;
04780 ++n;
04781 found = 1;
04782 break;
04783 }
04784 }
04785 if (found)
04786 break;
04787 }
04788 }
04789
04790
04791
04792
04793
04794
04795 found = 1;
04796 while (ilambda[n-1] < nlines - 1 && found) {
04797
04798
04799
04800
04801
04802
04803 if (n > 1)
04804 disp = (lambda[n-1] - lambda[n-2]) / (xpos[n-1] - xpos[n-2]);
04805 else
04806 disp = 0.0;
04807
04808 if (disp > max_disp || disp < min_disp)
04809 break;
04810
04811
04812
04813
04814
04815
04816
04817 hi_start = xpos[n-1] + (line[ilambda[n-1] + 1] - lambda[n-1]) / disp;
04818
04819
04820
04821
04822
04823
04824
04825
04826
04827 found = 0;
04828 min = fabs(peak[0] - hi_start);
04829 minpos = 0;
04830 for (k = 1; k < npeaks; k++) {
04831 if (min > fabs(peak[k] - hi_start)) {
04832 min = fabs(peak[k] - hi_start);
04833 minpos = k;
04834 }
04835 }
04836 if (min < 6 && fabs(peak[minpos] - xpos[n-1]) > 1.0) {
04837 xpos[n] = peak[minpos];
04838 lambda[n] = line[ilambda[n-1] + 1];
04839 ilambda[n] = ilambda[n-1] + 1;
04840 ++n;
04841 found = 1;
04842 }
04843 }
04844
04845
04846
04847
04848
04849
04850 found = 1;
04851 while (ilambda[0] > 0 && found) {
04852
04853
04854
04855
04856
04857
04858 disp = (lambda[1] - lambda[0]) / (xpos[1] - xpos[0]);
04859
04860 if (disp > max_disp || disp < min_disp)
04861 break;
04862
04863
04864
04865
04866
04867
04868
04869 hi_start = xpos[0] - (lambda[0] - line[ilambda[0] - 1]) / disp;
04870
04871
04872
04873
04874
04875
04876
04877
04878
04879
04880 found = 0;
04881 min = fabs(peak[0] - hi_start);
04882 minpos = 0;
04883 for (k = 1; k < npeaks; k++) {
04884 if (min > fabs(peak[k] - hi_start)) {
04885 min = fabs(peak[k] - hi_start);
04886 minpos = k;
04887 }
04888 }
04889 if (min < 6 && fabs(peak[minpos] - xpos[0]) > 1.0) {
04890 for (j = n; j > 0; j--) {
04891 xpos[j] = xpos[j-1];
04892 lambda[j] = lambda[j-1];
04893 ilambda[j] = ilambda[j-1];
04894 }
04895 xpos[0] = peak[minpos];
04896 lambda[0] = line[ilambda[0] - 1];
04897 ilambda[0] = ilambda[0] - 1;
04898 ++n;
04899 found = 1;
04900 }
04901 }
04902 }
04903
04904
04905
04906
04907
04908
04909
04910
04911
04912
04913
04914
04915
04916
04917
04918
04919
04920
04921
04922
04923 for (i = 0; i < npeaks; i++)
04924 cpl_free(ident[i]);
04925 cpl_free(ident);
04926 cpl_free(nident);
04927 cpl_free(lident);
04928 cpl_free(ilambda);
04929 cpl_free(tmp_xpos);
04930 cpl_free(tmp_lambda);
04931 cpl_free(tmp_ilambda);
04932 cpl_free(peak_lo);
04933 cpl_free(flag);
04934 cpl_free(seq_length);
04935 cpl_free(peak_hi);
04936
04937 if (n == 0) {
04938 cpl_free(xpos);
04939 cpl_free(lambda);
04940 return NULL;
04941 }
04942
04943 return cpl_bivector_wrap_vectors(cpl_vector_wrap(n, xpos),
04944 cpl_vector_wrap(n, lambda));
04945 }
04946
04947
04965
04966
04967
04968
04969
04970
04971
04972
04973
04974
04975
04976
04977
04978
04979
04980
04981
04982
04983
04984
04985
04986
04987
04988
04989
04990
04991
04992
04993
04994
04995
04996
04997
04998
04999
05000
05001
05002
05003
05004
05005 double mos_eval_dds(cpl_polynomial *ids, double blue, double red,
05006 double refwave, double pixel)
05007 {
05008 double yellow;
05009 double coeff;
05010 cpl_size zero = 0;
05011
05012 if (cpl_polynomial_eval_1d(ids, blue-refwave, NULL) > pixel)
05013 return 0.0;
05014
05015 if (cpl_polynomial_eval_1d(ids, red-refwave, NULL) < pixel)
05016 return 0.0;
05017
05018 yellow = (blue + red) / 2 - refwave;
05019
05020 coeff = cpl_polynomial_get_coeff(ids, &zero);
05021 cpl_polynomial_set_coeff(ids, &zero, coeff - pixel);
05022
05023 cpl_polynomial_solve_1d(ids, yellow, &yellow, 1);
05024 if (cpl_error_get_code() != CPL_ERROR_NONE) {
05025 cpl_error_reset();
05026 return 0.0;
05027 }
05028
05029 cpl_polynomial_set_coeff(ids, &zero, coeff);
05030
05031 return yellow + refwave;
05032
05033 }
05034
05060 cpl_polynomial *mos_poly_wav2pix(cpl_bivector *pixwav, int order,
05061 double reject, int minlines,
05062 int *nlines, double *err,
05063 cpl_bivector **pixwav_used)
05064 {
05065 const char *func = "mos_poly_wav2pix";
05066
05067 cpl_bivector *pixwav2;
05068 cpl_vector *wavel;
05069 cpl_vector *pixel;
05070 double *d_wavel;
05071 double *d_pixel;
05072 double pixpos;
05073 int fitlines;
05074 int rejection = 0;
05075 int i, j;
05076
05077 cpl_polynomial *ids;
05078
05079
05080 *nlines = 0;
05081 *err = 0;
05082
05083 if (pixwav == NULL) {
05084 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05085 return NULL;
05086 }
05087
05088 fitlines = cpl_bivector_get_size(pixwav);
05089
05090 if (fitlines < minlines) {
05091 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05092 return NULL;
05093 }
05094
05095
05096
05097
05098
05099
05100
05101 if (reject > 0.0)
05102 rejection = 1;
05103
05104 if (rejection)
05105 pixwav2 = cpl_bivector_duplicate(pixwav);
05106 else
05107 pixwav2 = pixwav;
05108
05109
05110
05111
05112
05113
05114
05115 pixel = cpl_bivector_get_x(pixwav2);
05116 wavel = cpl_bivector_get_y(pixwav2);
05117
05118
05119
05120
05121
05122
05123 if (rejection)
05124 cpl_bivector_unwrap_vectors(pixwav2);
05125
05126
05127
05128
05129
05130
05131 while (fitlines >= minlines) {
05132
05133 ids = cpl_polynomial_fit_1d_create(wavel, pixel, order, err);
05134 *err = sqrt(*err);
05135
05136 if (ids == NULL) {
05137 cpl_msg_debug(cpl_error_get_where(), "%s", cpl_error_get_message());
05138 cpl_msg_debug(func, "Fitting IDS");
05139 cpl_error_set_where(func);
05140 if (rejection) {
05141 cpl_vector_delete(wavel);
05142 cpl_vector_delete(pixel);
05143 }
05144 return NULL;
05145 }
05146
05147 if (rejection) {
05148 cpl_vector * wavel_used = cpl_vector_duplicate(wavel);
05149 cpl_vector * pixel_used = cpl_vector_duplicate(pixel);
05150
05151
05152
05153
05154
05155
05156 d_pixel = cpl_vector_unwrap(pixel);
05157 d_wavel = cpl_vector_unwrap(wavel);
05158
05159 for (i = 0, j = 0; i < fitlines; i++) {
05160 pixpos = cpl_polynomial_eval_1d(ids, d_wavel[i], NULL);
05161 if (fabs(pixpos - d_pixel[i]) < reject) {
05162 d_pixel[j] = d_pixel[i];
05163 d_wavel[j] = d_wavel[i];
05164 j++;
05165 }
05166 }
05167
05168 if (j == fitlines) {
05169 cpl_bivector * pixwav_used_temp =
05170 cpl_bivector_wrap_vectors(pixel_used, wavel_used);
05171 *pixwav_used = cpl_bivector_duplicate(pixwav_used_temp);
05172 cpl_bivector_unwrap_vectors(pixwav_used_temp);
05173 cpl_vector_delete(wavel_used);
05174 cpl_vector_delete(pixel_used);
05175 cpl_free(d_wavel);
05176 cpl_free(d_pixel);
05177 *nlines = fitlines;
05178 return ids;
05179 }
05180 else {
05181 fitlines = j;
05182 cpl_polynomial_delete(ids);
05183 if (fitlines >= minlines) {
05184 pixel = cpl_vector_wrap(fitlines, d_pixel);
05185 wavel = cpl_vector_wrap(fitlines, d_wavel);
05186 }
05187 else {
05188 cpl_free(d_wavel);
05189 cpl_free(d_pixel);
05190 cpl_error_set(func, CPL_ERROR_CONTINUE);
05191 return NULL;
05192 }
05193 }
05194 cpl_vector_delete(wavel_used);
05195 cpl_vector_delete(pixel_used);
05196 }
05197 else {
05198 *nlines = fitlines;
05199 *pixwav_used = cpl_bivector_duplicate(pixwav2);
05200 return ids;
05201 }
05202 }
05203
05204 return ids;
05205 }
05206
05207
05232 cpl_polynomial *mos_poly_pix2wav(cpl_bivector *pixwav, int order,
05233 double reject, int minlines,
05234 int *nlines, double *err)
05235 {
05236
05237 cpl_bivector *wavpix;
05238 cpl_vector *wavel;
05239 cpl_vector *pixel;
05240
05241 cpl_polynomial *dds;
05242
05243 cpl_bivector *wavepix_used;
05244
05245
05246
05247
05248
05249
05250 pixel = cpl_bivector_get_x(pixwav);
05251 wavel = cpl_bivector_get_y(pixwav);
05252
05253 wavpix = cpl_bivector_wrap_vectors(wavel, pixel);
05254
05255 dds = mos_poly_wav2pix(wavpix, order, reject, minlines, nlines, err,
05256 &wavepix_used);
05257
05258 cpl_bivector_unwrap_vectors(wavpix);
05259
05260 cpl_bivector_delete(wavepix_used);
05261
05262 return dds;
05263
05264 }
05265
05266
05289 cpl_bivector *mos_find_peaks(const float *spectrum, int length,
05290 cpl_vector *lines, cpl_polynomial *ids,
05291 double refwave, int sradius)
05292 {
05293 const char *func = "mos_find_peaks";
05294
05295 double *data;
05296 double *d_pixel;
05297 double *d_wavel;
05298 float pos;
05299 int nlines;
05300 int pixel;
05301 int i, j;
05302
05303
05304 if (spectrum == NULL || lines == NULL || ids == NULL) {
05305 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05306 return NULL;
05307 }
05308
05309 nlines = cpl_vector_get_size(lines);
05310
05311 if (sradius < 1 || length < 2*sradius+1 || nlines < 1) {
05312 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05313 return NULL;
05314 }
05315
05316 d_wavel = cpl_malloc(nlines * sizeof(double));
05317 d_pixel = cpl_malloc(nlines * sizeof(double));
05318
05319 data = cpl_vector_get_data(lines);
05320
05321 for (i = 0, j = 0; i < nlines; i++) {
05322 pixel = cpl_polynomial_eval_1d(ids, data[i]-refwave, NULL) + 0.5;
05323 if (pixel < 0 || pixel - sradius < 0 || pixel + sradius >= length)
05324 continue;
05325 if (peakPosition(spectrum+pixel-sradius, 2*sradius+1, &pos, 1) == 0) {
05326 pos += pixel - sradius;
05327 d_pixel[j] = pos;
05328 d_wavel[j] = data[i];
05329 j++;
05330 }
05331 }
05332
05333 if (j > 0) {
05334 return cpl_bivector_wrap_vectors(cpl_vector_wrap(j, d_pixel),
05335 cpl_vector_wrap(j, d_wavel));
05336 }
05337 else {
05338 cpl_free(d_wavel);
05339 cpl_free(d_pixel);
05340 cpl_error_set(func, CPL_ERROR_ILLEGAL_OUTPUT);
05341 return NULL;
05342 }
05343 }
05344
05345
05469 cpl_image *mos_wavelength_calibration_raw(const cpl_image *image,
05470 cpl_vector *lines,
05471 double dispersion, float level,
05472 int sradius, int order,
05473 double reject, double refwave,
05474 double *wavestart, double *waveend,
05475 int *nlines, double *error,
05476 cpl_table *idscoeff,
05477 cpl_image *calibration,
05478 cpl_image *residuals,
05479 cpl_table *restable,
05480 cpl_mask *refmask,
05481 cpl_table *detected_lines)
05482 {
05483
05484 const char *func = "mos_wavelength_calibration_raw";
05485
05486 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
05487
05488
05489 double tolerance = 20.0;
05490 int step = 10;
05491
05492 char name[MAX_COLNAME];
05493 cpl_image *resampled;
05494 cpl_bivector *output;
05495 cpl_bivector *new_output;
05496 cpl_vector *peaks;
05497 cpl_vector *wavel;
05498 cpl_polynomial *ids;
05499 cpl_polynomial *lin;
05500 cpl_matrix *kernel;
05501 double ids_err;
05502 double max_disp, min_disp;
05503 double *line;
05504 double firstLambda, lastLambda, lambda;
05505 double value, wave, pixe;
05506 cpl_binary *mdata;
05507 const float *sdata;
05508 float *rdata;
05509 float *idata;
05510 float *ddata;
05511 float v1, v2, vi;
05512 float fpixel;
05513 int *have_it;
05514 int pixstart, pixend;
05515 int extrapolation;
05516 int nref;
05517 int nl, nx, ny, pixel;
05518 int countLines, usedLines;
05519 int uorder;
05520 int in, first, last;
05521 int width, uradius;
05522 int i, j;
05523 int null;
05524 cpl_size k;
05525
05526
05527 if (dispersion == 0.0) {
05528 cpl_msg_error(func, "The expected dispersion (A/pixel) must be given");
05529 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05530 return NULL;
05531 }
05532
05533 if (dispersion < 0.0) {
05534 cpl_msg_error(func, "The expected dispersion must be positive");
05535 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05536 return NULL;
05537 }
05538
05539 max_disp = dispersion + dispersion * tolerance / 100;
05540 min_disp = dispersion - dispersion * tolerance / 100;
05541
05542 if (order < 1) {
05543 cpl_msg_error(func, "The order of the fitting polynomial "
05544 "must be at least 1");
05545 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
05546 return NULL;
05547 }
05548
05549 if (image == NULL || lines == NULL) {
05550 cpl_msg_error(func, "Both spectral exposure and reference line "
05551 "catalog are required in input");
05552 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
05553 return NULL;
05554 }
05555
05556 nx = cpl_image_get_size_x(image);
05557 ny = cpl_image_get_size_y(image);
05558 sdata = cpl_image_get_data_float_const(image);
05559
05560 nref = cpl_vector_get_size(lines);
05561 line = cpl_vector_get_data(lines);
05562
05563 if (*wavestart < 1.0 && *waveend < 1.0) {
05564 firstLambda = line[0];
05565 lastLambda = line[nref-1];
05566 extrapolation = (lastLambda - firstLambda) / 10;
05567 firstLambda -= extrapolation;
05568 lastLambda += extrapolation;
05569 *wavestart = firstLambda;
05570 *waveend = lastLambda;
05571 }
05572 else {
05573 firstLambda = *wavestart;
05574 lastLambda = *waveend;
05575 }
05576
05577 nl = (lastLambda - firstLambda) / dispersion;
05578 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
05579 rdata = cpl_image_get_data_float(resampled);
05580
05581 if (calibration)
05582 idata = cpl_image_get_data_float(calibration);
05583
05584 if (residuals)
05585 ddata = cpl_image_get_data_float(residuals);
05586
05587 if (idscoeff)
05588 for (j = 0; j <= order; j++)
05589 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
05590
05591 if (restable) {
05592 cpl_table_set_size(restable, nref);
05593 cpl_table_new_column(restable, "wavelength", CPL_TYPE_DOUBLE);
05594 cpl_table_copy_data_double(restable, "wavelength", line);
05595 for (i = 0; i < ny; i += step) {
05596 snprintf(name, MAX_COLNAME, "r%d", i);
05597 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05598 snprintf(name, MAX_COLNAME, "d%d", i);
05599 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05600 snprintf(name, MAX_COLNAME, "p%d", i);
05601 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
05602 }
05603 }
05604
05605 if (detected_lines) {
05606 cpl_table_set_size(detected_lines, 0);
05607 cpl_table_new_column(detected_lines, "xpos", CPL_TYPE_DOUBLE);
05608 cpl_table_new_column(detected_lines, "ypos", CPL_TYPE_DOUBLE);
05609 cpl_table_new_column(detected_lines, "xpos_iter", CPL_TYPE_DOUBLE);
05610 cpl_table_new_column(detected_lines, "ypos_iter", CPL_TYPE_DOUBLE);
05611 cpl_table_new_column(detected_lines, "peak_flux", CPL_TYPE_DOUBLE);
05612 cpl_table_new_column(detected_lines, "wave_ident", CPL_TYPE_DOUBLE);
05613 cpl_table_new_column(detected_lines, "wave_ident_iter", CPL_TYPE_DOUBLE);
05614 cpl_table_new_column(detected_lines, "xpos_fit_rect_wavecal", CPL_TYPE_DOUBLE);
05615 cpl_table_new_column(detected_lines, "res_xpos", CPL_TYPE_DOUBLE);
05616 cpl_table_new_column(detected_lines, "fit_used", CPL_TYPE_INT);
05617 }
05618
05619
05620
05621
05622
05623
05624
05625 for (i = 0; i < ny; i++) {
05626 width = mos_lines_width(sdata + i*nx, nx);
05627 if (sradius > 0) {
05628 if (width > sradius) {
05629 uradius = width;
05630 }
05631 else {
05632 uradius = sradius;
05633 }
05634 }
05635 if (width < 5)
05636 width = 5;
05637 peaks = mos_peak_candidates(sdata + i*nx, nx, level, width);
05638 if (peaks) {
05639 peaks = mos_refine_peaks(sdata + i*nx, nx, peaks, width);
05640 }
05641 if (peaks) {
05642 output = mos_identify_peaks(peaks, lines, min_disp, max_disp, 0.05);
05643 if (output) {
05644 cpl_bivector * peaks_ident_used_fit;
05645 countLines = cpl_bivector_get_size(output);
05646 if (countLines < 4) {
05647 cpl_bivector_delete(output);
05648 cpl_vector_delete(peaks);
05649 if (nlines)
05650 nlines[i] = 0;
05651 if (error)
05652 error[i] = 0.0;
05653 continue;
05654 }
05655
05656
05657
05658
05659
05660 wavel = cpl_bivector_get_y(output);
05661 cpl_vector_subtract_scalar(wavel, refwave);
05662
05663 uorder = countLines / 2 - 1;
05664 if (uorder > order)
05665 uorder = order;
05666
05667
05668
05669
05670
05671
05672
05673
05674
05675
05676 ids = mos_poly_wav2pix(output, uorder, reject,
05677 2 * (uorder + 1), &usedLines,
05678 &ids_err, &peaks_ident_used_fit);
05679
05680 if (ids == NULL) {
05681 cpl_bivector_delete(output);
05682 cpl_vector_delete(peaks);
05683 if (nlines)
05684 nlines[i] = 0;
05685 if (error)
05686 error[i] = 0.0;
05687 cpl_error_reset();
05688 continue;
05689 }
05690
05691 if (idscoeff) {
05692
05693
05694
05695
05696
05697
05698
05699 for (k = 0; k <= order; k++) {
05700 if (k > uorder) {
05701 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
05702 }
05703 else {
05704 cpl_table_set_double(idscoeff, clab[k], i,
05705 cpl_polynomial_get_coeff(ids, &k));
05706 }
05707 }
05708 }
05709
05710 if(detected_lines)
05711 {
05712 cpl_size newlines = cpl_vector_get_size(peaks);
05713 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
05714 cpl_table_set_size(detected_lines, oldsize + newlines);
05715 for(cpl_size iline = 0; iline < newlines; ++iline)
05716 {
05717 cpl_table_set_double(detected_lines, "xpos",
05718 oldsize + iline, cpl_vector_get(peaks, iline) + 1);
05719 cpl_table_set_double(detected_lines, "ypos",
05720 oldsize + iline, (double)i + 1);
05721 cpl_table_set_double(detected_lines, "peak_flux",
05722 oldsize + iline,
05723 sdata[i*nx+(int)(cpl_vector_get(peaks, iline)+0.5)]);
05724 cpl_table_set_int(detected_lines,
05725 "fit_used",
05726 oldsize + iline, 0);
05727 }
05728 }
05729
05730
05731
05732 if(detected_lines)
05733 {
05734 cpl_size nidentlines = cpl_bivector_get_size(output);
05735 cpl_size ndetectlines = cpl_vector_get_size(peaks);
05736 cpl_size totalsize = cpl_table_get_nrow(detected_lines);
05737 for(cpl_size idline = 0; idline < nidentlines; ++idline)
05738 {
05739 for(cpl_size detline = 0; detline < ndetectlines; ++detline)
05740 {
05741 if(cpl_vector_get(peaks, detline) ==
05742 cpl_bivector_get_x_data(output)[idline])
05743 {
05744 cpl_size table_pos = totalsize - ndetectlines + detline;
05745 double wave_ident = cpl_bivector_get_y_data(output)[idline] + refwave;
05746 double xpix_fit = cpl_polynomial_eval_1d(ids,
05747 wave_ident - refwave, NULL);
05748 double xpos_det = cpl_table_get_double(detected_lines,
05749 "xpos",
05750 table_pos, &null);
05751 cpl_table_set_double(detected_lines,
05752 "wave_ident",
05753 table_pos,
05754 wave_ident);
05755 cpl_table_set_double(detected_lines,
05756 "xpos_fit_rect_wavecal",
05757 table_pos,
05758 xpix_fit + 1);
05759 cpl_table_set_double(detected_lines,
05760 "res_xpos",
05761 table_pos,
05762 xpos_det - xpix_fit - 1);
05763 cpl_table_set_int(detected_lines,
05764 "fit_used",
05765 table_pos, 0);
05766 for(cpl_size i_used = 0; i_used < cpl_bivector_get_size(peaks_ident_used_fit); ++i_used)
05767 {
05768 if(cpl_bivector_get_x_data(output)[idline] == cpl_bivector_get_x_data(peaks_ident_used_fit)[i_used])
05769 cpl_table_set_int(detected_lines,
05770 "fit_used",
05771 table_pos, 1);
05772 }
05773 }
05774 }
05775 }
05776 }
05777
05778 if (sradius > 0) {
05779 cpl_bivector * peaks_ident_used_fit;
05780
05781
05782
05783
05784
05785 new_output = mos_find_peaks(sdata + i*nx, nx, lines,
05786 ids, refwave, uradius);
05787
05788 if (new_output) {
05789 cpl_bivector_delete(output);
05790 output = new_output;
05791 }
05792 else
05793 cpl_error_reset();
05794
05795
05796 cpl_polynomial_delete(ids);
05797
05798 countLines = cpl_bivector_get_size(output);
05799
05800 if (countLines < 4) {
05801 cpl_bivector_delete(output);
05802 cpl_vector_delete(peaks);
05803
05804
05805
05806
05807
05808
05809
05810 if (nlines)
05811 nlines[i] = 0;
05812 if (error)
05813 error[i] = 0.0;
05814 if (idscoeff)
05815 for (k = 0; k <= order; k++)
05816 cpl_table_set_invalid(idscoeff, clab[k], i);
05817 continue;
05818 }
05819
05820 wavel = cpl_bivector_get_y(output);
05821 cpl_vector_subtract_scalar(wavel, refwave);
05822
05823 uorder = countLines / 2 - 1;
05824 if (uorder > order)
05825 uorder = order;
05826
05827 ids = mos_poly_wav2pix(output, uorder, reject,
05828 2 * (uorder + 1), &usedLines,
05829 &ids_err, &peaks_ident_used_fit);
05830
05831 if (ids == NULL) {
05832 cpl_bivector_delete(output);
05833 cpl_vector_delete(peaks);
05834
05835
05836
05837
05838
05839
05840
05841 if (nlines)
05842 nlines[i] = 0;
05843 if (error)
05844 error[i] = 0.0;
05845 if (idscoeff)
05846 for (k = 0; k <= order; k++)
05847 cpl_table_set_invalid(idscoeff, clab[k], i);
05848 cpl_error_reset();
05849 continue;
05850 }
05851
05852 if (idscoeff) {
05853 for (k = 0; k <= order; k++) {
05854 if (k > uorder) {
05855 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
05856 }
05857 else {
05858 cpl_table_set_double(idscoeff, clab[k], i,
05859 cpl_polynomial_get_coeff(ids, &k));
05860 }
05861 }
05862 }
05863
05864
05865 if(detected_lines)
05866 {
05867 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
05868 cpl_size nidentlines = cpl_bivector_get_size(output);
05869 cpl_table_set_size(detected_lines, oldsize + nidentlines);
05870 for(cpl_size idline = 0; idline < nidentlines ; ++idline)
05871 {
05872 double wave_ident = cpl_bivector_get_y_data(output)[idline] + refwave;
05873 double xpix_fit = cpl_polynomial_eval_1d(ids,
05874 wave_ident - refwave, NULL);
05875 cpl_table_set_double(detected_lines, "xpos_iter",
05876 oldsize + idline, cpl_bivector_get_x_data(output)[idline] + 1);
05877 cpl_table_set_double(detected_lines, "ypos_iter",
05878 oldsize + idline, (double)i + 1);
05879 cpl_table_set_double(detected_lines, "peak_flux",
05880 oldsize + idline,
05881 sdata[i*nx+(int)(cpl_bivector_get_x_data(output)[idline]+0.5)]);
05882 cpl_table_set_double(detected_lines, "wave_ident_iter",
05883 oldsize + idline, wave_ident);
05884 cpl_table_set_double(detected_lines, "xpos_fit_rect_wavecal",
05885 oldsize + idline, xpix_fit + 1);
05886 }
05887 }
05888
05889 }
05890
05891 if (nlines)
05892 nlines[i] = usedLines;
05893 if (error)
05894 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
05895
05896 pixstart = cpl_polynomial_eval_1d(ids,
05897 cpl_bivector_get_y_data(output)[0], NULL);
05898 pixend = cpl_polynomial_eval_1d(ids,
05899 cpl_bivector_get_y_data(output)[countLines-1], NULL);
05900 extrapolation = (pixend - pixstart) / 5;
05901 pixstart -= extrapolation;
05902 pixend += extrapolation;
05903 if (pixstart < 0)
05904 pixstart = 0;
05905 if (pixend > nx)
05906 pixend = nx;
05907
05908
05909
05910
05911
05912 if (calibration) {
05913 for (j = pixstart; j < pixend; j++) {
05914 (idata + i*nx)[j] = mos_eval_dds(ids, firstLambda,
05915 lastLambda, refwave,
05916 j);
05917 }
05918 }
05919
05920
05921
05922
05923
05924 for (j = 0; j < nl; j++) {
05925 lambda = firstLambda + j * dispersion;
05926 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
05927 NULL);
05928 pixel = fpixel;
05929 if (pixel >= 0 && pixel < nx-1) {
05930 v1 = (sdata + i*nx)[pixel];
05931 v2 = (sdata + i*nx)[pixel+1];
05932 vi = v1 + (v2-v1)*(fpixel-pixel);
05933 (rdata + i*nl)[j] = vi;
05934 }
05935 }
05936
05937
05938
05939
05940
05941 if (residuals || (restable && !(i%step))) {
05942 if (restable && !(i%step)) {
05943 lin = cpl_polynomial_new(1);
05944 for (k = 0; k < 2; k++)
05945 cpl_polynomial_set_coeff(lin, &k,
05946 cpl_polynomial_get_coeff(ids, &k));
05947 }
05948 for (j = 0; j < countLines; j++) {
05949 pixe = cpl_bivector_get_x_data(output)[j];
05950 wave = cpl_bivector_get_y_data(output)[j];
05951 value = pixe - cpl_polynomial_eval_1d(ids, wave, NULL);
05952 if (residuals) {
05953 pixel = pixe + 0.5;
05954 (ddata + i*nx)[pixel] = value;
05955 }
05956 if (restable && !(i%step)) {
05957 for (k = 0; k < nref; k++) {
05958 if (fabs(line[k] - refwave - wave) < 0.1) {
05959 snprintf(name, MAX_COLNAME, "r%d", i);
05960 cpl_table_set_double(restable, name,
05961 k, value);
05962 value = pixe
05963 - cpl_polynomial_eval_1d(lin, wave,
05964 NULL);
05965 snprintf(name, MAX_COLNAME, "d%d", i);
05966 cpl_table_set_double(restable, name,
05967 k, value);
05968 snprintf(name, MAX_COLNAME, "p%d", i);
05969 cpl_table_set_double(restable, name,
05970 k, pixe);
05971 break;
05972 }
05973 }
05974 }
05975 }
05976 if (restable && !(i%step)) {
05977 cpl_polynomial_delete(lin);
05978 }
05979 }
05980
05981
05982
05983
05984
05985 if (refmask) {
05986 mdata = cpl_mask_get_data(refmask);
05987 pixel = cpl_polynomial_eval_1d(ids, 0.0, NULL) + 0.5;
05988 if (pixel - 1 >= 0 && pixel + 1 < nx) {
05989 mdata[pixel-1 + i*nx] = CPL_BINARY_1;
05990 mdata[pixel + i*nx] = CPL_BINARY_1;
05991 mdata[pixel+1 + i*nx] = CPL_BINARY_1;
05992 }
05993 }
05994
05995 cpl_polynomial_delete(ids);
05996 cpl_bivector_delete(output);
05997 }
05998 cpl_vector_delete(peaks);
05999 }
06000 }
06001
06002 if (refmask) {
06003 kernel = cpl_matrix_new(3, 3);
06004 cpl_matrix_set(kernel, 0, 1, 1.0);
06005 cpl_matrix_set(kernel, 1, 1, 1.0);
06006 cpl_matrix_set(kernel, 2, 1, 1.0);
06007
06008 cpl_mask_dilation(refmask, kernel);
06009 cpl_mask_erosion(refmask, kernel);
06010 cpl_mask_erosion(refmask, kernel);
06011 cpl_mask_dilation(refmask, kernel);
06012
06013 cpl_matrix_delete(kernel);
06014
06015
06016
06017
06018
06019 mdata = cpl_mask_get_data(refmask);
06020 have_it = cpl_calloc(ny, sizeof(int));
06021
06022 for (i = 0; i < ny; i++, mdata += nx) {
06023 for (j = 0; j < nx; j++) {
06024 if (mdata[j] == CPL_BINARY_1) {
06025 have_it[i] = j;
06026 break;
06027 }
06028 }
06029 }
06030
06031 mdata = cpl_mask_get_data(refmask);
06032 in = 0;
06033 first = last = 0;
06034
06035 for (i = 0; i < ny; i++) {
06036 if (have_it[i]) {
06037 if (!in) {
06038 in = 1;
06039 if (first) {
06040 last = i;
06041 if (abs(have_it[first] - have_it[last]) < 3) {
06042 for (j = first; j < last; j++) {
06043 mdata[have_it[first] + nx*j + 0] = CPL_BINARY_1;
06044 mdata[have_it[first] + nx*j + 1] = CPL_BINARY_1;
06045 mdata[have_it[first] + nx*j + 2] = CPL_BINARY_1;
06046 }
06047 }
06048 }
06049 }
06050 }
06051 else {
06052 if (in) {
06053 in = 0;
06054 first = i - 1;
06055 }
06056 }
06057 }
06058
06059 cpl_free(have_it);
06060
06061 }
06062
06063
06064
06065
06066
06067
06068
06069
06070
06071
06072
06073 return resampled;
06074 }
06075
06076
06098
06099
06100
06101
06102
06103
06104
06105
06106
06107
06108
06109
06110
06111
06112
06113
06114
06115
06116
06117
06118
06119
06120
06121
06122
06123
06124
06125
06126
06127
06128
06129
06130
06131
06132
06133
06134
06135
06136
06137
06138
06139
06140
06141
06142
06143
06144
06145
06146
06147
06148
06149
06150
06151
06152
06153
06154
06155
06156
06157
06158
06159
06160
06161
06162
06163
06185 cpl_table *mos_locate_spectra(cpl_mask *mask)
06186 {
06187 const char *func = "mos_locate_spectra";
06188
06189 cpl_apertures *slits;
06190 cpl_image *labimage;
06191 cpl_image *refimage;
06192 cpl_table *slitpos;
06193 cpl_propertylist *sort_col;
06194 cpl_size nslits;
06195 int i;
06196
06197
06198 if (mask == NULL) {
06199 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
06200 return NULL;
06201 }
06202
06203 labimage = cpl_image_labelise_mask_create(mask, &nslits);
06204
06205 if (nslits < 1) {
06206 cpl_image_delete(labimage);
06207 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
06208 return NULL;
06209 }
06210
06211 refimage = cpl_image_new_from_mask(mask);
06212
06213 slits = cpl_apertures_new_from_image(refimage, labimage);
06214
06215 cpl_image_delete(labimage);
06216 cpl_image_delete(refimage);
06217
06218 nslits = cpl_apertures_get_size(slits);
06219 if (nslits < 1) {
06220 cpl_apertures_delete(slits);
06221 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
06222 return NULL;
06223 }
06224
06225 slitpos = cpl_table_new(nslits);
06226 cpl_table_new_column(slitpos, "xtop", CPL_TYPE_DOUBLE);
06227 cpl_table_new_column(slitpos, "ytop", CPL_TYPE_DOUBLE);
06228 cpl_table_new_column(slitpos, "xbottom", CPL_TYPE_DOUBLE);
06229 cpl_table_new_column(slitpos, "ybottom", CPL_TYPE_DOUBLE);
06230 cpl_table_set_column_unit(slitpos, "xtop", "pixel");
06231 cpl_table_set_column_unit(slitpos, "ytop", "pixel");
06232 cpl_table_set_column_unit(slitpos, "xbottom", "pixel");
06233 cpl_table_set_column_unit(slitpos, "ybottom", "pixel");
06234
06235 for (i = 0; i < nslits; i++) {
06236 cpl_table_set_double(slitpos, "xtop", i,
06237 cpl_apertures_get_top_x(slits, i+1) - 1);
06238 cpl_table_set_double(slitpos, "ytop", i,
06239 cpl_apertures_get_top(slits, i+1));
06240 cpl_table_set_double(slitpos, "xbottom", i,
06241 cpl_apertures_get_bottom_x(slits, i+1) - 1);
06242 cpl_table_set_double(slitpos, "ybottom", i,
06243 cpl_apertures_get_bottom(slits, i+1));
06244 }
06245
06246 cpl_apertures_delete(slits);
06247
06248 sort_col = cpl_propertylist_new();
06249 cpl_propertylist_append_bool(sort_col, "ytop", 1);
06250 cpl_table_sort(slitpos, sort_col);
06251 cpl_propertylist_delete(sort_col);
06252
06253 return slitpos;
06254
06255 }
06256
06257
06273 cpl_error_code mos_validate_slits(cpl_table *slits)
06274 {
06275 const char *func = "mos_validate_slits";
06276
06277
06278 if (slits == NULL)
06279 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
06280
06281 if (1 != cpl_table_has_column(slits, "xtop"))
06282 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
06283
06284 if (1 != cpl_table_has_column(slits, "ytop"))
06285 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
06286
06287 if (1 != cpl_table_has_column(slits, "xbottom"))
06288 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
06289
06290 if (1 != cpl_table_has_column(slits, "ybottom"))
06291 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
06292
06293 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "xtop"))
06294 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
06295
06296 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "ytop"))
06297 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
06298
06299 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "xbottom"))
06300 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
06301
06302 if (CPL_TYPE_DOUBLE != cpl_table_get_column_type(slits, "ybottom"))
06303 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
06304
06305 return CPL_ERROR_NONE;
06306 }
06307
06308
06337 cpl_error_code mos_rotate_slits(cpl_table *slits, int rotation, int nx, int ny)
06338 {
06339 const char *func = "mos_rotate_slits";
06340
06341 cpl_error_code error;
06342 char aux_name[] = "_0";
06343 int i;
06344
06345
06346 rotation %= 4;
06347 if (rotation < 0)
06348 rotation += 4;
06349
06350 if (rotation == 0)
06351 return CPL_ERROR_NONE;
06352
06353 error = mos_validate_slits(slits);
06354 if (error)
06355 return cpl_error_set(func, error);
06356
06357 if (rotation == 1 || rotation == 3) {
06358
06359
06360
06361
06362
06363 for (i = 0; i < 77; i++)
06364 if (1 == cpl_table_has_column(slits, aux_name))
06365 aux_name[1]++;
06366 if (1 == cpl_table_has_column(slits, aux_name))
06367 return cpl_error_set(func, CPL_ERROR_CONTINUE);
06368 cpl_table_name_column(slits, "xtop", aux_name);
06369 cpl_table_name_column(slits, "ytop", "xtop");
06370 cpl_table_name_column(slits, aux_name, "ytop");
06371 cpl_table_name_column(slits, "xbottom", aux_name);
06372 cpl_table_name_column(slits, "ybottom", "xbottom");
06373 cpl_table_name_column(slits, aux_name, "ybottom");
06374 }
06375
06376 if (rotation == 1 || rotation == 2) {
06377 cpl_table_multiply_scalar(slits, "xtop", -1.0);
06378 cpl_table_multiply_scalar(slits, "xbottom", -1.0);
06379 cpl_table_add_scalar(slits, "xtop", nx);
06380 cpl_table_add_scalar(slits, "xbottom", nx);
06381 }
06382
06383 if (rotation == 3 || rotation == 2) {
06384 cpl_table_multiply_scalar(slits, "ytop", -1.0);
06385 cpl_table_multiply_scalar(slits, "ybottom", -1.0);
06386 cpl_table_add_scalar(slits, "ytop", ny);
06387 cpl_table_add_scalar(slits, "ybottom", ny);
06388 }
06389
06390 return CPL_ERROR_NONE;
06391 }
06392
06393
06451 cpl_table *mos_identify_slits(cpl_table *slits, cpl_table *maskslits,
06452 cpl_table *global)
06453 {
06454 cpl_array *top_ident = NULL;;
06455 cpl_array *bot_ident = NULL;;
06456 cpl_matrix *mdata;
06457 cpl_matrix *mpattern;
06458 cpl_matrix *top_data;
06459 cpl_matrix *top_pattern;
06460 cpl_matrix *top_mdata;
06461 cpl_matrix *top_mpattern;
06462 cpl_matrix *bot_data;
06463 cpl_matrix *bot_pattern;
06464 cpl_matrix *bot_mdata;
06465 cpl_matrix *bot_mpattern;
06466 cpl_propertylist *sort_col;
06467 double *xtop;
06468 double *ytop;
06469 double *xmtop;
06470 double *ymtop;
06471 double *xbot;
06472 double *ybot;
06473 double *xmbot;
06474 double *ymbot;
06475 double top_scale, bot_scale;
06476 double angle, top_angle, bot_angle;
06477 double xmse, ymse;
06478 double xrms, top_xrms, bot_xrms;
06479 double yrms, top_yrms, bot_yrms;
06480 int nslits;
06481 int nmaskslits, use_pattern;
06482 int found_slits, found_slits_top, found_slits_bot;
06483 int i;
06484 cpl_table *positions;
06485 cpl_error_code error;
06486
06487 cpl_vector *point;
06488 double *dpoint;
06489 cpl_vector *xpos;
06490 cpl_vector *ypos;
06491 cpl_vector *xmpos;
06492 cpl_vector *ympos;
06493 cpl_bivector *mpos;
06494 cpl_polynomial *xpoly = NULL;
06495 cpl_polynomial *ypoly = NULL;
06496 cpl_polynomial *top_xpoly = NULL;
06497 cpl_polynomial *top_ypoly = NULL;
06498 cpl_polynomial *bot_xpoly = NULL;
06499 cpl_polynomial *bot_ypoly = NULL;
06500
06501 char *msg_multiplex = " ";
06502
06503
06504 error = mos_validate_slits(slits);
06505 if (error) {
06506 cpl_msg_error(cpl_func, "CCD slits table validation: %s",
06507 cpl_error_get_message());
06508 cpl_error_set(cpl_func, error);
06509 return NULL;
06510 }
06511
06512 error = mos_validate_slits(maskslits);
06513 if (error) {
06514 cpl_msg_error(cpl_func, "Mask slits table validation: %s",
06515 cpl_error_get_message());
06516 cpl_error_set(cpl_func, error);
06517 return NULL;
06518 }
06519
06520 if (1 != cpl_table_has_column(maskslits, "slit_id")) {
06521 cpl_msg_error(cpl_func, "Missing slits identifiers");
06522 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
06523 return NULL;
06524 }
06525
06526 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits, "slit_id")) {
06527 cpl_msg_error(cpl_func, "Wrong type used for slits identifiers");
06528 cpl_error_set(cpl_func, CPL_ERROR_INVALID_TYPE);
06529 return NULL;
06530 }
06531
06532 nslits = cpl_table_get_nrow(slits);
06533 nmaskslits = cpl_table_get_nrow(maskslits);
06534
06535 if (nslits == 0 || nmaskslits == 0) {
06536 cpl_msg_error(cpl_func, "Empty slits table");
06537 cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
06538 return NULL;
06539 }
06540
06541 if (nslits > 100 && mos_multiplex < 0) {
06542 cpl_msg_info(cpl_func, "Many slits: using 'fast' pattern matching...");
06543 positions = mos_identify_slits_fast(slits, maskslits, global);
06544 if (positions == NULL)
06545 cpl_error_set_where(cpl_func);
06546 return positions;
06547 }
06548
06549
06550
06551
06552
06553 sort_col = cpl_propertylist_new();
06554 cpl_propertylist_append_bool(sort_col, "ytop", 1);
06555 cpl_table_sort(slits, sort_col);
06556 cpl_table_sort(maskslits, sort_col);
06557 cpl_propertylist_delete(sort_col);
06558
06559
06560
06561
06562
06563 if (nslits < 3 && nmaskslits > nslits) {
06564
06565
06566
06567
06568
06569
06570
06571
06572 if (nslits > 1)
06573 cpl_msg_warning(cpl_func, "Cannot match the %d found CCD slits "
06574 "with the %d mask slits: process will continue "
06575 "using the detected CCD slits positions", nslits,
06576 nmaskslits);
06577 else
06578 cpl_msg_warning(cpl_func, "Cannot match the found CCD slit with "
06579 "the %d mask slits: process will continue using "
06580 "the detected CCD slit position", nmaskslits);
06581 return NULL;
06582 }
06583
06584 if (nmaskslits < 3 && nslits > nmaskslits) {
06585
06586
06587
06588
06589
06590
06591
06592 cpl_msg_warning(cpl_func, "Cannot match the %d found CCD slits with "
06593 "the %d mask slits: process will continue using "
06594 "the detected CCD slits positions", nslits,
06595 nmaskslits);
06596 return NULL;
06597 }
06598
06599
06600
06601
06602
06603
06604
06605
06606 xtop = cpl_table_get_data_double(slits, "xtop");
06607 ytop = cpl_table_get_data_double(slits, "ytop");
06608 xmtop = cpl_table_get_data_double(maskslits, "xtop");
06609 ymtop = cpl_table_get_data_double(maskslits, "ytop");
06610
06611 xbot = cpl_table_get_data_double(slits, "xbottom");
06612 ybot = cpl_table_get_data_double(slits, "ybottom");
06613 xmbot = cpl_table_get_data_double(maskslits, "xbottom");
06614 ymbot = cpl_table_get_data_double(maskslits, "ybottom");
06615
06616 top_data = cpl_matrix_new(2, nslits);
06617 top_pattern = cpl_matrix_new(2, nmaskslits);
06618 bot_data = cpl_matrix_new(2, nslits);
06619 bot_pattern = cpl_matrix_new(2, nmaskslits);
06620
06621 for (i = 0; i < nslits; i++)
06622 cpl_matrix_set(top_data, 0, i, xtop[i]);
06623
06624 for (i = 0; i < nslits; i++)
06625 cpl_matrix_set(top_data, 1, i, ytop[i]);
06626
06627 for (i = 0; i < nmaskslits; i++)
06628 cpl_matrix_set(top_pattern, 0, i, xmtop[i]);
06629
06630 for (i = 0; i < nmaskslits; i++)
06631 cpl_matrix_set(top_pattern, 1, i, ymtop[i]);
06632
06633 for (i = 0; i < nslits; i++)
06634 cpl_matrix_set(bot_data, 0, i, xbot[i]);
06635
06636 for (i = 0; i < nslits; i++)
06637 cpl_matrix_set(bot_data, 1, i, ybot[i]);
06638
06639 for (i = 0; i < nmaskslits; i++)
06640 cpl_matrix_set(bot_pattern, 0, i, xmbot[i]);
06641
06642 for (i = 0; i < nmaskslits; i++)
06643 cpl_matrix_set(bot_pattern, 1, i, ymbot[i]);
06644
06645 if (nmaskslits > nslits)
06646 use_pattern = nslits;
06647 else
06648 use_pattern = nmaskslits;
06649
06650 top_ident = cpl_ppm_match_points(top_data, nslits, 1.0, top_pattern,
06651 use_pattern, 0.0, 0.1, 5, &top_mdata,
06652 &top_mpattern, &top_scale, &top_angle);
06653
06654 bot_ident = cpl_ppm_match_points(bot_data, nslits, 1.0, bot_pattern,
06655 use_pattern, 0.0, 0.1, 5, &bot_mdata,
06656 &bot_mpattern, &bot_scale, &bot_angle);
06657 cpl_matrix_delete(top_data);
06658 cpl_matrix_delete(top_pattern);
06659 cpl_matrix_delete(bot_data);
06660 cpl_matrix_delete(bot_pattern);
06661
06662 if (top_ident == NULL && bot_ident == NULL) {
06663 cpl_msg_warning(cpl_func, "Pattern matching failure: cannot match "
06664 "the %d found CCD slits with the %d mask slits: "
06665 "process will continue using the detected CCD "
06666 "slits positions", nslits, nmaskslits);
06667 return NULL;
06668 }
06669
06670 found_slits_top = 0;
06671 found_slits_bot = 0;
06672 if (top_ident && bot_ident) {
06673 cpl_msg_info(cpl_func, "Median platescale: %f +/- %f pixel/mm",
06674 (top_scale + bot_scale) / 2, fabs(top_scale - bot_scale));
06675 cpl_msg_info(cpl_func, "Median rotation: %f +/- %f degrees",
06676 (top_angle + bot_angle) / 2, fabs(top_angle - bot_angle));
06677 if (fabs(top_angle) < fabs(bot_angle))
06678 angle = fabs(top_angle);
06679 else
06680 angle = fabs(bot_angle);
06681 found_slits_top = cpl_matrix_get_ncol(top_mdata);
06682 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
06683 }
06684 else if (top_ident) {
06685 cpl_msg_info(cpl_func, "Median platescale: %f pixel/mm", top_scale);
06686 cpl_msg_info(cpl_func, "Median rotation: %f degrees", top_angle);
06687 angle = fabs(top_angle);
06688 found_slits_top = cpl_matrix_get_ncol(top_mdata);
06689 }
06690 else {
06691 cpl_msg_info(cpl_func, "Median platescale: %f pixel/mm", bot_scale);
06692 cpl_msg_info(cpl_func, "Median rotation: %f degrees", bot_angle);
06693 angle = fabs(bot_angle);
06694 found_slits_bot = cpl_matrix_get_ncol(bot_mdata);
06695 }
06696
06697 cpl_array_delete(top_ident);
06698 cpl_array_delete(bot_ident);
06699
06700 if (angle > 4.0) {
06701 cpl_msg_warning(cpl_func, "Uncertain pattern matching: the rotation "
06702 "angle is expected to be around zero. This match is "
06703 "rejected: the process will continue using the %d "
06704 "detected CCD slits positions", nslits);
06705 return NULL;
06706 }
06707
06708 found_slits = found_slits_top;
06709 if (found_slits < found_slits_bot)
06710 found_slits = found_slits_bot;
06711
06712 if (found_slits < 4) {
06713 cpl_msg_warning(cpl_func,
06714 "Too few safely identified slits: %d out of %d "
06715 "candidates (%d expected). Process will continue "
06716 "using the detected CCD slits positions", found_slits,
06717 nslits, nmaskslits);
06718 return NULL;
06719 }
06720
06721 cpl_msg_info(cpl_func, "Preliminary identified slits: %d out of %d "
06722 "candidates\n(%d expected)", found_slits, nslits,
06723 nmaskslits);
06724
06725 if (found_slits_top < 4)
06726 found_slits_top = 0;
06727
06728 if (found_slits_bot < 4)
06729 found_slits_bot = 0;
06730
06731
06732
06733
06734
06735
06736
06737 for (i = 0; i < 2; i++) {
06738 cpl_size mindeg2d[] = {0, 0};
06739 cpl_size maxdeg2d[2];
06740 cpl_vector * fitresidual;
06741 if (i) {
06742 found_slits = found_slits_top;
06743 mdata = top_mdata;
06744 mpattern = top_mpattern;
06745 }
06746 else {
06747 found_slits = found_slits_bot;
06748 mdata = bot_mdata;
06749 mpattern = bot_mpattern;
06750 }
06751
06752 if (found_slits == 0)
06753 continue;
06754 else if (found_slits < 10)
06755 maxdeg2d[0] = maxdeg2d[1] = 1;
06756 else
06757 maxdeg2d[0] = maxdeg2d[1] = 2;
06758
06759 xpos = cpl_vector_wrap(found_slits,
06760 cpl_matrix_get_data(mdata) );
06761 ypos = cpl_vector_wrap(found_slits,
06762 cpl_matrix_get_data(mdata) + found_slits);
06763 xmpos = cpl_vector_wrap(found_slits,
06764 cpl_matrix_get_data(mpattern) );
06765 ympos = cpl_vector_wrap(found_slits,
06766 cpl_matrix_get_data(mpattern) + found_slits);
06767 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
06768 fitresidual = cpl_vector_new(cpl_vector_get_size(xpos));
06769 xpoly = cpl_polynomial_new(2);
06770 cpl_polynomial_fit(xpoly, mpattern, NULL, xpos, NULL, CPL_FALSE, mindeg2d, maxdeg2d);
06771 cpl_vector_fill_polynomial_fit_residual(fitresidual, xpos, NULL, xpoly, mpattern, NULL);
06772 xmse = cpl_vector_product(fitresidual, fitresidual)
06773 / cpl_vector_get_size(fitresidual);
06774 ypoly = cpl_polynomial_new(2);
06775 cpl_polynomial_fit(ypoly, mpattern, NULL, ypos, NULL, CPL_FALSE, mindeg2d, maxdeg2d);
06776 cpl_vector_fill_polynomial_fit_residual(fitresidual, ypos, NULL, ypoly, mpattern, NULL);
06777 ymse = cpl_vector_product(fitresidual, fitresidual)
06778 / cpl_vector_get_size(fitresidual);
06779
06780 cpl_bivector_unwrap_vectors(mpos);
06781 cpl_vector_unwrap(xpos);
06782 cpl_vector_unwrap(ypos);
06783 cpl_vector_unwrap(xmpos);
06784 cpl_vector_unwrap(ympos);
06785 cpl_matrix_delete(mdata);
06786 cpl_matrix_delete(mpattern);
06787 cpl_vector_delete(fitresidual);
06788
06789 if (i) {
06790 top_xpoly = xpoly;
06791 top_ypoly = ypoly;
06792 top_xrms = sqrt(xmse*2*maxdeg2d[0]/(found_slits - 1));
06793 top_yrms = sqrt(ymse*2*maxdeg2d[0]/(found_slits - 1));
06794 }
06795 else {
06796 bot_xpoly = xpoly;
06797 bot_ypoly = ypoly;
06798 bot_xrms = sqrt(xmse*2*maxdeg2d[0]/(found_slits - 1));
06799 bot_yrms = sqrt(ymse*2*maxdeg2d[0]/(found_slits - 1));
06800 }
06801 }
06802
06803 if (top_xpoly && bot_xpoly) {
06804 if (top_xrms < bot_xrms) {
06805 xrms = top_xrms;
06806 xpoly = top_xpoly;
06807 cpl_polynomial_delete(bot_xpoly);
06808 }
06809 else {
06810 xrms = bot_xrms;
06811 xpoly = bot_xpoly;
06812 cpl_polynomial_delete(top_xpoly);
06813 }
06814 }
06815 else if (top_xpoly) {
06816 xrms = top_xrms;
06817 xpoly = top_xpoly;
06818 }
06819 else {
06820 xrms = bot_xrms;
06821 xpoly = bot_xpoly;
06822 }
06823
06824 if (top_ypoly && bot_ypoly) {
06825 if (top_yrms < bot_yrms) {
06826 yrms = top_yrms;
06827 ypoly = top_ypoly;
06828 cpl_polynomial_delete(bot_ypoly);
06829 }
06830 else {
06831 yrms = bot_yrms;
06832 ypoly = bot_ypoly;
06833 cpl_polynomial_delete(top_ypoly);
06834 }
06835 }
06836 else if (top_ypoly) {
06837 yrms = top_yrms;
06838 ypoly = top_ypoly;
06839 }
06840 else {
06841 yrms = bot_yrms;
06842 ypoly = bot_ypoly;
06843 }
06844
06845 if (xpoly == NULL || ypoly == NULL) {
06846 cpl_msg_warning(cpl_func, "Fit failure: the accuracy of the "
06847 "identified slits positions cannot be improved.");
06848 cpl_polynomial_delete(xpoly);
06849 cpl_polynomial_delete(ypoly);
06850 cpl_error_reset();
06851 return NULL;
06852 }
06853
06854 cpl_msg_info(cpl_func,
06855 "Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
06856 xrms, yrms);
06857
06858 if (global) {
06859 write_global_distortion(global, 0, xpoly);
06860 write_global_distortion(global, 7, ypoly);
06861 }
06862
06863
06864
06865
06866
06867
06868 positions = cpl_table_duplicate(maskslits);
06869 cpl_table_duplicate_column(positions, "xmtop", positions, "xtop");
06870 cpl_table_duplicate_column(positions, "ymtop", positions, "ytop");
06871 cpl_table_duplicate_column(positions, "xmbottom", positions, "xbottom");
06872 cpl_table_duplicate_column(positions, "ymbottom", positions, "ybottom");
06873
06874 point = cpl_vector_new(2);
06875 dpoint = cpl_vector_get_data(point);
06876
06877 for (i = 0; i < nmaskslits; i++) {
06878 double position_x;
06879 double position_y;
06880
06881 dpoint[0] = cpl_table_get_double(positions, "xmtop", i, NULL);
06882 dpoint[1] = cpl_table_get_double(positions, "ymtop", i, NULL);
06883 position_x = cpl_polynomial_eval(xpoly, point);
06884
06885
06886
06887
06888
06889
06890 cpl_table_set_double(positions, "xtop", i, position_x);
06891 position_y = cpl_polynomial_eval(ypoly, point);
06892 cpl_table_set_double(positions, "ytop", i, position_y);
06893 dpoint[0] = cpl_table_get_double(positions, "xmbottom", i, NULL);
06894 dpoint[1] = cpl_table_get_double(positions, "ymbottom", i, NULL);
06895 position_x = cpl_polynomial_eval(xpoly, point);
06896 cpl_table_set_double(positions, "xbottom", i, position_x);
06897 position_y = cpl_polynomial_eval(ypoly, point);
06898 cpl_table_set_double(positions, "ybottom", i, position_y);
06899 }
06900
06901
06902
06903
06904
06905
06906
06907 cpl_vector_delete(point);
06908 cpl_polynomial_delete(xpoly);
06909 cpl_polynomial_delete(ypoly);
06910
06911 cpl_table_erase_column(positions, "xmtop");
06912 cpl_table_erase_column(positions, "ymtop");
06913 cpl_table_erase_column(positions, "xmbottom");
06914 cpl_table_erase_column(positions, "ymbottom");
06915
06916 if (mos_multiplex >= 0) {
06917 msg_multiplex =
06918 cpl_sprintf("in the CCD section between %d and %d pixel",
06919 mos_multiplex * mos_region_size,
06920 (mos_multiplex + 1) * mos_region_size);
06921 }
06922
06923 if (nmaskslits > nslits)
06924 cpl_msg_info(cpl_func,
06925 "Finally identified slits: %d out of %d expected %s\n"
06926 "(%d recovered)", nmaskslits, nmaskslits, msg_multiplex,
06927 nmaskslits - nslits);
06928 else if (nmaskslits < nslits)
06929 cpl_msg_info(cpl_func,
06930 "Finally identified slits: %d out of %d expected %s\n"
06931 "(%d rejected)", nmaskslits, nmaskslits, msg_multiplex,
06932 nslits - nmaskslits);
06933 else
06934 cpl_msg_info(cpl_func,
06935 "Finally identified slits: %d out of %d expected %s",
06936 nmaskslits, nmaskslits, msg_multiplex);
06937
06938 if (mos_multiplex >= 0) {
06939 cpl_free(msg_multiplex);
06940 }
06941
06942 return positions;
06943
06944 }
06945
06946
06947 cpl_table *mos_identify_slits_fast(cpl_table *slits, cpl_table *maskslits,
06948 cpl_table *global)
06949 {
06950 const char *func = "mos_identify_slits_fast";
06951
06952 cpl_propertylist *sort_col;
06953 cpl_table *positions;
06954 cpl_vector *scales;
06955 cpl_vector *angles;
06956 cpl_vector *point;
06957 cpl_vector *xpos;
06958 cpl_vector *ypos;
06959 cpl_vector *xmpos;
06960 cpl_vector *ympos;
06961 cpl_bivector *mpos;
06962 cpl_polynomial *xpoly = NULL;
06963 cpl_polynomial *ypoly = NULL;
06964 cpl_error_code error;
06965 int nslits;
06966 int nmaskslits;
06967 int found_slits;
06968 int i, j, k;
06969
06970 double dist1, dist2, dist3, dist, mindist;
06971 double scale, minscale, maxscale;
06972 double angle, minangle, maxangle;
06973 double *dscale;
06974 double *dangle;
06975 double *dpoint;
06976 double *xtop;
06977 double *ytop;
06978 double *xbottom;
06979 double *ybottom;
06980 double *xcenter;
06981 double *ycenter;
06982 double *xpseudo;
06983 double *ypseudo;
06984 int *slit_id;
06985 double *xmtop;
06986 double *ymtop;
06987 double *xmbottom;
06988 double *ymbottom;
06989 double *xmcenter;
06990 double *ymcenter;
06991 double *xmpseudo;
06992 double *ympseudo;
06993 double xmse, ymse;
06994 int *mslit_id;
06995 int *good;
06996 int minpos;
06997 int degree;
06998
06999 double sradius = 0.01;
07000 int in_sradius;
07001
07002 double pi = 3.14159265358979323846;
07003
07004
07005 error = mos_validate_slits(slits);
07006 if (error) {
07007 cpl_msg_error(func, "CCD slits table validation: %s",
07008 cpl_error_get_message());
07009 cpl_error_set(func, error);
07010 return NULL;
07011 }
07012
07013 error = mos_validate_slits(maskslits);
07014 if (error) {
07015 cpl_msg_error(func, "Mask slits table validation: %s",
07016 cpl_error_get_message());
07017 cpl_error_set(func, error);
07018 return NULL;
07019 }
07020
07021 if (1 != cpl_table_has_column(maskslits, "slit_id")) {
07022 cpl_msg_error(func, "Missing slits identifiers");
07023 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
07024 return NULL;
07025 }
07026
07027 if (CPL_TYPE_INT != cpl_table_get_column_type(maskslits, "slit_id")) {
07028 cpl_msg_error(func, "Wrong type used for slits identifiers");
07029 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
07030 return NULL;
07031 }
07032
07033 nslits = cpl_table_get_nrow(slits);
07034 nmaskslits = cpl_table_get_nrow(maskslits);
07035
07036 if (nslits == 0 || nmaskslits == 0) {
07037 cpl_msg_error(func, "Empty slits table");
07038 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07039 return NULL;
07040 }
07041
07042
07043
07044
07045
07046
07047
07048 if (cpl_table_has_column(slits, "xcenter"))
07049 cpl_table_erase_column(slits, "xcenter");
07050
07051 if (cpl_table_has_column(slits, "ycenter"))
07052 cpl_table_erase_column(slits, "ycenter");
07053
07054 if (cpl_table_has_column(maskslits, "xcenter"))
07055 cpl_table_erase_column(maskslits, "xcenter");
07056
07057 if (cpl_table_has_column(maskslits, "ycenter"))
07058 cpl_table_erase_column(maskslits, "ycenter");
07059
07060 cpl_table_duplicate_column(slits, "xcenter", slits, "xtop");
07061 cpl_table_add_columns(slits, "xcenter", "xbottom");
07062 cpl_table_divide_scalar(slits, "xcenter", 2.0);
07063 cpl_table_duplicate_column(slits, "ycenter", slits, "ytop");
07064 cpl_table_add_columns(slits, "ycenter", "ybottom");
07065 cpl_table_divide_scalar(slits, "ycenter", 2.0);
07066
07067 cpl_table_duplicate_column(maskslits, "xcenter", maskslits, "xtop");
07068 cpl_table_add_columns(maskslits, "xcenter", "xbottom");
07069 cpl_table_divide_scalar(maskslits, "xcenter", 2.0);
07070 cpl_table_duplicate_column(maskslits, "ycenter", maskslits, "ytop");
07071 cpl_table_add_columns(maskslits, "ycenter", "ybottom");
07072 cpl_table_divide_scalar(maskslits, "ycenter", 2.0);
07073
07074
07075
07076
07077
07078
07079 sort_col = cpl_propertylist_new();
07080 cpl_propertylist_append_bool(sort_col, "ycenter", 1);
07081 cpl_table_sort(slits, sort_col);
07082 cpl_table_sort(maskslits, sort_col);
07083 cpl_propertylist_delete(sort_col);
07084
07085
07086
07087
07088
07089
07090 if (nslits < 3 && nmaskslits > nslits) {
07091
07092
07093
07094
07095
07096
07097
07098
07099 if (nslits > 1)
07100 cpl_msg_warning(func, "Cannot match the found CCD slit with the "
07101 "%d mask slits: process will continue using the "
07102 "detected CCD slit position", nmaskslits);
07103 else
07104 cpl_msg_warning(func, "Cannot match the %d found CCD slits with "
07105 "the %d mask slits: process will continue using "
07106 "the detected CCD slits positions", nslits,
07107 nmaskslits);
07108 return NULL;
07109 }
07110
07111 if (nslits <= 3 && nslits == nmaskslits) {
07112
07113 cpl_msg_warning(func, "Too few slits (%d) on mask and CCD", nslits);
07114 cpl_msg_warning(func, "Their detected positions are left unchanged");
07115
07116
07117
07118
07119
07120
07121
07122
07123
07124
07125 positions = cpl_table_duplicate(slits);
07126 cpl_table_erase_column(slits, "xcenter");
07127 cpl_table_erase_column(slits, "ycenter");
07128 cpl_table_duplicate_column(positions, "xmtop", maskslits, "xtop");
07129 cpl_table_duplicate_column(positions, "ymtop", maskslits, "ytop");
07130 cpl_table_duplicate_column(positions, "xmbottom", maskslits, "xbottom");
07131 cpl_table_duplicate_column(positions, "ymbottom", maskslits, "ybottom");
07132 cpl_table_duplicate_column(positions, "xmcenter", maskslits, "xcenter");
07133 cpl_table_duplicate_column(positions, "ymcenter", maskslits, "ycenter");
07134 cpl_table_duplicate_column(positions, "slit_id", maskslits, "slit_id");
07135 cpl_table_erase_column(maskslits, "xcenter");
07136 cpl_table_erase_column(maskslits, "ycenter");
07137
07138 if (nslits > 1) {
07139 xcenter = cpl_table_get_data_double(positions, "xcenter");
07140 ycenter = cpl_table_get_data_double(positions, "ycenter");
07141 xmcenter = cpl_table_get_data_double(positions, "xmcenter");
07142 ymcenter = cpl_table_get_data_double(positions, "ymcenter");
07143
07144 dist1 = (xcenter[0] - xcenter[1])*(xcenter[0] - xcenter[1])
07145 + (ycenter[0] - ycenter[1])*(ycenter[0] - ycenter[1]);
07146 dist2 = (xmcenter[0] - xmcenter[1])*(xmcenter[0] - xmcenter[1])
07147 + (ymcenter[0] - ymcenter[1])*(ymcenter[0] - ymcenter[1]);
07148 scale = sqrt(dist1/dist2);
07149
07150 if (nslits == 3) {
07151 dist1 = (xcenter[1] - xcenter[2])*(xcenter[1] - xcenter[2])
07152 + (ycenter[1] - ycenter[2])*(ycenter[1] - ycenter[2]);
07153 dist2 = (xmcenter[1] - xmcenter[2])*(xmcenter[1] - xmcenter[2])
07154 + (ymcenter[1] - ymcenter[2])*(ymcenter[1] - ymcenter[2]);
07155 scale += sqrt(dist1/dist2);
07156 scale /= 2;
07157 }
07158
07159 cpl_msg_info(func, "Platescale: %f pixel/mm", scale);
07160 }
07161
07162 return positions;
07163 }
07164
07165 if (nmaskslits < 3 && nslits > nmaskslits) {
07166
07167
07168
07169
07170
07171
07172
07173 cpl_msg_warning(func, "Cannot match the %d found CCD slits with "
07174 "the %d mask slits: process will continue using "
07175 "the detected CCD slits positions", nslits,
07176 nmaskslits);
07177 return NULL;
07178 }
07179
07180
07181
07182
07183
07184
07185
07186
07187
07188
07189
07190
07191
07192
07193
07194
07195
07196
07197
07198
07199
07200
07201
07202
07203
07204
07205
07206
07207 if (cpl_table_has_column(slits, "xpseudo"))
07208 cpl_table_erase_column(slits, "xpseudo");
07209
07210 if (cpl_table_has_column(slits, "ypseudo"))
07211 cpl_table_erase_column(slits, "ypseudo");
07212
07213 if (cpl_table_has_column(maskslits, "xpseudo"))
07214 cpl_table_erase_column(maskslits, "xpseudo");
07215
07216 if (cpl_table_has_column(maskslits, "ypseudo"))
07217 cpl_table_erase_column(maskslits, "ypseudo");
07218
07219 cpl_table_duplicate_column(slits, "xpseudo", slits, "xcenter");
07220 cpl_table_duplicate_column(slits, "ypseudo", slits, "ycenter");
07221
07222 xcenter = cpl_table_get_data_double(slits, "xcenter");
07223 ycenter = cpl_table_get_data_double(slits, "ycenter");
07224 xpseudo = cpl_table_get_data_double(slits, "xpseudo");
07225 ypseudo = cpl_table_get_data_double(slits, "ypseudo");
07226
07227 for (i = 1; i < nslits - 1; i++) {
07228 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
07229 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
07230 dist2 = (xcenter[i-1] - xcenter[i+1]) * (xcenter[i-1] - xcenter[i+1])
07231 + (ycenter[i-1] - ycenter[i+1]) * (ycenter[i-1] - ycenter[i+1]);
07232 dist3 = (xcenter[i] - xcenter[i+1]) * (xcenter[i] - xcenter[i+1])
07233 + (ycenter[i] - ycenter[i+1]) * (ycenter[i] - ycenter[i+1]);
07234 xpseudo[i] = sqrt(dist1/dist2);
07235 ypseudo[i] = sqrt(dist3/dist2);
07236 }
07237
07238 cpl_table_set_invalid(slits, "xpseudo", 0);
07239 cpl_table_set_invalid(slits, "xpseudo", nslits-1);
07240 cpl_table_set_invalid(slits, "ypseudo", 0);
07241 cpl_table_set_invalid(slits, "ypseudo", nslits-1);
07242
07243 cpl_table_duplicate_column(maskslits, "xpseudo", maskslits, "xcenter");
07244 cpl_table_duplicate_column(maskslits, "ypseudo", maskslits, "ycenter");
07245
07246 xcenter = cpl_table_get_data_double(maskslits, "xcenter");
07247 ycenter = cpl_table_get_data_double(maskslits, "ycenter");
07248 xmpseudo = cpl_table_get_data_double(maskslits, "xpseudo");
07249 ympseudo = cpl_table_get_data_double(maskslits, "ypseudo");
07250
07251 for (i = 1; i < nmaskslits - 1; i++) {
07252 dist1 = (xcenter[i-1] - xcenter[i])*(xcenter[i-1] - xcenter[i])
07253 + (ycenter[i-1] - ycenter[i])*(ycenter[i-1] - ycenter[i]);
07254 dist2 = (xcenter[i-1] - xcenter[i+1])*(xcenter[i-1] - xcenter[i+1])
07255 + (ycenter[i-1] - ycenter[i+1])*(ycenter[i-1] - ycenter[i+1]);
07256 dist3 = (xcenter[i] - xcenter[i+1])*(xcenter[i] - xcenter[i+1])
07257 + (ycenter[i] - ycenter[i+1])*(ycenter[i] - ycenter[i+1]);
07258 xmpseudo[i] = sqrt(dist1/dist2);
07259 ympseudo[i] = sqrt(dist3/dist2);
07260 }
07261
07262 cpl_table_set_invalid(maskslits, "xpseudo", 0);
07263 cpl_table_set_invalid(maskslits, "xpseudo", nmaskslits-1);
07264 cpl_table_set_invalid(maskslits, "ypseudo", 0);
07265 cpl_table_set_invalid(maskslits, "ypseudo", nmaskslits-1);
07266
07267
07268
07269
07270
07271
07272
07273
07274
07275
07276
07277 if (cpl_table_has_column(slits, "slit_id"))
07278 cpl_table_erase_column(slits, "slit_id");
07279 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
07280 slit_id = cpl_table_get_data_int(maskslits, "slit_id");
07281
07282 for (i = 1; i < nmaskslits - 1; i++) {
07283 in_sradius = 0;
07284 mindist = (xmpseudo[i] - xpseudo[1]) * (xmpseudo[i] - xpseudo[1])
07285 + (ympseudo[i] - ypseudo[1]) * (ympseudo[i] - ypseudo[1]);
07286 minpos = 1;
07287 if (mindist < sradius*sradius)
07288 in_sradius++;
07289 for (j = 2; j < nslits - 1; j++) {
07290 dist = (xmpseudo[i] - xpseudo[j]) * (xmpseudo[i] - xpseudo[j])
07291 + (ympseudo[i] - ypseudo[j]) * (ympseudo[i] - ypseudo[j]);
07292 if (dist < sradius*sradius)
07293 in_sradius++;
07294 if (in_sradius > 1)
07295 break;
07296 if (mindist > dist) {
07297 mindist = dist;
07298 minpos = j;
07299 }
07300 }
07301
07302 mindist = sqrt(mindist);
07303
07304 if (mindist < sradius && in_sradius == 1) {
07305 cpl_table_set_int(slits, "slit_id", minpos-1, slit_id[i-1]);
07306 cpl_table_set_int(slits, "slit_id", minpos, slit_id[i]);
07307 cpl_table_set_int(slits, "slit_id", minpos+1, slit_id[i+1]);
07308 }
07309 }
07310
07311
07312
07313
07314
07315
07316
07317 found_slits = nslits - cpl_table_count_invalid(slits, "slit_id");
07318
07319 if (found_slits < 3) {
07320 cpl_msg_warning(func, "Too few preliminarily identified slits: "
07321 "%d out of %d", found_slits, nslits);
07322 if (nslits == nmaskslits) {
07323 cpl_msg_warning(func, "(this is not an error, it could be caused "
07324 "by a mask with regularly located slits)");
07325 cpl_msg_warning(func, "The detected slits positions are left "
07326 "unchanged");
07327
07328
07329
07330
07331
07332
07333
07334
07335 cpl_table_erase_column(slits, "slit_id");
07336 cpl_table_erase_column(slits, "xpseudo");
07337 cpl_table_erase_column(slits, "ypseudo");
07338 positions = cpl_table_duplicate(slits);
07339 cpl_table_erase_column(slits, "xcenter");
07340 cpl_table_erase_column(slits, "ycenter");
07341
07342 cpl_table_erase_column(maskslits, "xpseudo");
07343 cpl_table_erase_column(maskslits, "ypseudo");
07344 cpl_table_duplicate_column(positions, "xmtop",
07345 maskslits, "xtop");
07346 cpl_table_duplicate_column(positions, "ymtop",
07347 maskslits, "ytop");
07348 cpl_table_duplicate_column(positions, "xmbottom",
07349 maskslits, "xbottom");
07350 cpl_table_duplicate_column(positions, "ymbottom",
07351 maskslits, "ybottom");
07352 cpl_table_duplicate_column(positions, "xmcenter",
07353 maskslits, "xcenter");
07354 cpl_table_duplicate_column(positions, "ymcenter",
07355 maskslits, "ycenter");
07356 cpl_table_duplicate_column(positions, "slit_id",
07357 maskslits, "slit_id");
07358 cpl_table_erase_column(maskslits, "xcenter");
07359 cpl_table_erase_column(maskslits, "ycenter");
07360 return positions;
07361 }
07362 else {
07363 cpl_table_erase_column(slits, "slit_id");
07364 cpl_table_erase_column(slits, "xpseudo");
07365 cpl_table_erase_column(slits, "ypseudo");
07366 positions = cpl_table_duplicate(slits);
07367 cpl_table_erase_column(slits, "xcenter");
07368 cpl_table_erase_column(slits, "ycenter");
07369 cpl_msg_warning(func, "(the failure could be caused "
07370 "by a mask with regularly located slits)");
07371 return NULL;
07372 }
07373 }
07374 else {
07375 cpl_msg_info(func, "Preliminarily identified slits: %d out of %d "
07376 "candidates (%d expected)", found_slits, nslits,
07377 nmaskslits);
07378 }
07379
07380
07381
07382
07383
07384
07385
07386
07387 positions = cpl_table_new(found_slits);
07388 cpl_table_new_column(positions, "slit_id", CPL_TYPE_INT);
07389 cpl_table_new_column(positions, "xtop", CPL_TYPE_DOUBLE);
07390 cpl_table_new_column(positions, "ytop", CPL_TYPE_DOUBLE);
07391 cpl_table_new_column(positions, "xbottom", CPL_TYPE_DOUBLE);
07392 cpl_table_new_column(positions, "ybottom", CPL_TYPE_DOUBLE);
07393 cpl_table_new_column(positions, "xcenter", CPL_TYPE_DOUBLE);
07394 cpl_table_new_column(positions, "ycenter", CPL_TYPE_DOUBLE);
07395 cpl_table_new_column(positions, "xmtop", CPL_TYPE_DOUBLE);
07396 cpl_table_new_column(positions, "ymtop", CPL_TYPE_DOUBLE);
07397 cpl_table_new_column(positions, "xmbottom", CPL_TYPE_DOUBLE);
07398 cpl_table_new_column(positions, "ymbottom", CPL_TYPE_DOUBLE);
07399 cpl_table_new_column(positions, "xmcenter", CPL_TYPE_DOUBLE);
07400 cpl_table_new_column(positions, "ymcenter", CPL_TYPE_DOUBLE);
07401 cpl_table_new_column(positions, "good", CPL_TYPE_INT);
07402 cpl_table_fill_column_window_int(positions, "good", 0, found_slits, 0);
07403
07404 slit_id = cpl_table_get_data_int (slits, "slit_id");
07405 xtop = cpl_table_get_data_double(slits, "xtop");
07406 ytop = cpl_table_get_data_double(slits, "ytop");
07407 xbottom = cpl_table_get_data_double(slits, "xbottom");
07408 ybottom = cpl_table_get_data_double(slits, "ybottom");
07409 xcenter = cpl_table_get_data_double(slits, "xcenter");
07410 ycenter = cpl_table_get_data_double(slits, "ycenter");
07411
07412 mslit_id = cpl_table_get_data_int (maskslits, "slit_id");
07413 xmtop = cpl_table_get_data_double(maskslits, "xtop");
07414 ymtop = cpl_table_get_data_double(maskslits, "ytop");
07415 xmbottom = cpl_table_get_data_double(maskslits, "xbottom");
07416 ymbottom = cpl_table_get_data_double(maskslits, "ybottom");
07417 xmcenter = cpl_table_get_data_double(maskslits, "xcenter");
07418 ymcenter = cpl_table_get_data_double(maskslits, "ycenter");
07419
07420
07421
07422
07423
07424
07425
07426
07427 k = 0;
07428 cpl_table_fill_invalid_int(slits, "slit_id", 0);
07429 for (i = 0; i < nmaskslits; i++) {
07430 for (j = 0; j < nslits; j++) {
07431 if (slit_id[j] == 0)
07432 continue;
07433 if (mslit_id[i] == slit_id[j]) {
07434 cpl_table_set_int (positions, "slit_id", k, slit_id[j]);
07435
07436 cpl_table_set_double(positions, "xtop", k, xtop[j]);
07437 cpl_table_set_double(positions, "ytop", k, ytop[j]);
07438 cpl_table_set_double(positions, "xbottom", k, xbottom[j]);
07439 cpl_table_set_double(positions, "ybottom", k, ybottom[j]);
07440 cpl_table_set_double(positions, "xcenter", k, xcenter[j]);
07441 cpl_table_set_double(positions, "ycenter", k, ycenter[j]);
07442
07443 cpl_table_set_double(positions, "xmtop", k, xmtop[i]);
07444 cpl_table_set_double(positions, "ymtop", k, ymtop[i]);
07445 cpl_table_set_double(positions, "xmbottom", k, xmbottom[i]);
07446 cpl_table_set_double(positions, "ymbottom", k, ymbottom[i]);
07447 cpl_table_set_double(positions, "xmcenter", k, xmcenter[i]);
07448 cpl_table_set_double(positions, "ymcenter", k, ymcenter[i]);
07449
07450 k++;
07451
07452 break;
07453 }
07454 }
07455 }
07456
07457 found_slits = k;
07458
07459 cpl_table_erase_column(slits, "slit_id");
07460 cpl_table_erase_column(slits, "xpseudo");
07461 cpl_table_erase_column(slits, "ypseudo");
07462 cpl_table_erase_column(slits, "xcenter");
07463 cpl_table_erase_column(slits, "ycenter");
07464 cpl_table_erase_column(maskslits, "xpseudo");
07465 cpl_table_erase_column(maskslits, "ypseudo");
07466 cpl_table_erase_column(maskslits, "xcenter");
07467 cpl_table_erase_column(maskslits, "ycenter");
07468
07469
07470
07471
07472
07473
07474
07475
07476
07477 ytop = cpl_table_get_data_double(positions, "ytop");
07478 ybottom = cpl_table_get_data_double(positions, "ybottom");
07479 xcenter = cpl_table_get_data_double(positions, "xcenter");
07480 ycenter = cpl_table_get_data_double(positions, "ycenter");
07481 xmcenter = cpl_table_get_data_double(positions, "xmcenter");
07482 ymcenter = cpl_table_get_data_double(positions, "ymcenter");
07483
07484 scales = cpl_vector_new(found_slits - 1);
07485 dscale = cpl_vector_get_data(scales);
07486 angles = cpl_vector_new(found_slits - 1);
07487 dangle = cpl_vector_get_data(angles);
07488
07489 for (i = 1; i < found_slits; i++) {
07490 dist1 = (xcenter[i-1] - xcenter[i]) * (xcenter[i-1] - xcenter[i])
07491 + (ycenter[i-1] - ycenter[i]) * (ycenter[i-1] - ycenter[i]);
07492 dist2 = (xmcenter[i-1] - xmcenter[i]) * (xmcenter[i-1] - xmcenter[i])
07493 + (ymcenter[i-1] - ymcenter[i]) * (ymcenter[i-1] - ymcenter[i]);
07494 dscale[i-1] = sqrt(dist1/dist2);
07495 dangle[i-1] = atan2(ycenter[i-1] - ycenter[i],
07496 xcenter[i-1] - xcenter[i])
07497 - atan2(ymcenter[i-1] - ymcenter[i],
07498 xmcenter[i-1] - xmcenter[i]);
07499 dangle[i-1] *= 180;
07500 dangle[i-1] /= pi;
07501 }
07502
07503 minscale = cpl_vector_get_min(scales);
07504 scale = cpl_vector_get_median_const(scales);
07505 maxscale = cpl_vector_get_max(scales);
07506
07507 minangle = cpl_vector_get_min(angles);
07508 angle = cpl_vector_get_median_const(angles);
07509 maxangle = cpl_vector_get_max(angles);
07510
07511 cpl_msg_info(func, "Median platescale: %f pixel/mm", scale);
07512 cpl_msg_info(func, "Minmax platescale: %f, %f pixel/mm",
07513 minscale, maxscale);
07514
07515 cpl_msg_info(func, "Median rotation: %f degrees", angle);
07516 cpl_msg_info(func, "Minmax rotation: %f, %f degrees",
07517 minangle, maxangle);
07518
07519 good = cpl_table_get_data_int(positions, "good");
07520
07521 good[0] = good[found_slits - 1] = 1;
07522 for (i = 1; i < found_slits; i++) {
07523 if (fabs((dscale[i-1] - scale)/scale) < 0.10
07524 && fabs(dangle[i-1] - angle) < 2) {
07525 good[i-1]++;
07526 good[i]++;
07527 }
07528 }
07529
07530 for (i = 0; i < found_slits; i++) {
07531 if (good[i] < 2)
07532 good[i] = 0;
07533 else
07534 good[i] = 1;
07535 }
07536
07537
07538
07539
07540
07541
07542
07543
07544
07545
07546
07547
07548
07549
07550
07551
07552
07553
07554
07555
07556
07557
07558
07559
07560
07561
07562
07563
07564
07565
07566
07567
07568
07569
07570 cpl_vector_delete(scales);
07571 cpl_vector_delete(angles);
07572
07573 cpl_table_and_selected_int(positions, "good", CPL_EQUAL_TO, 0);
07574 cpl_table_erase_selected(positions);
07575 cpl_table_erase_column(positions, "good");
07576 found_slits = cpl_table_get_nrow(positions);
07577
07578 if (found_slits < 4) {
07579
07580
07581
07582
07583
07584
07585
07586 cpl_msg_warning(func, "Too few safely identified slits: %d out of %d "
07587 "candidates (%d expected). Process will continue "
07588 "using the detected CCD slits positions", found_slits,
07589 nslits, nmaskslits);
07590 cpl_table_delete(positions);
07591 return NULL;
07592 }
07593 else {
07594 cpl_msg_info(func, "Safely identified slits: %d out of %d "
07595 "candidates\n(%d expected)", found_slits, nslits,
07596 nmaskslits);
07597 }
07598
07599
07600
07601
07602
07603
07604
07605
07606 xpos = cpl_vector_wrap(found_slits,
07607 cpl_table_get_data_double(positions, "xcenter"));
07608 ypos = cpl_vector_wrap(found_slits,
07609 cpl_table_get_data_double(positions, "ycenter"));
07610 xmpos = cpl_vector_wrap(found_slits,
07611 cpl_table_get_data_double(positions, "xmcenter"));
07612 ympos = cpl_vector_wrap(found_slits,
07613 cpl_table_get_data_double(positions, "ymcenter"));
07614 mpos = cpl_bivector_wrap_vectors(xmpos, ympos);
07615
07616 if (found_slits < 10)
07617 degree = 1;
07618 else
07619 degree = 2;
07620
07621 xpoly = cpl_polynomial_fit_2d_create(mpos, xpos, degree, &xmse);
07622 if (xpoly != NULL)
07623 ypoly = cpl_polynomial_fit_2d_create(mpos, ypos, degree, &ymse);
07624 cpl_bivector_unwrap_vectors(mpos);
07625 cpl_vector_unwrap(xpos);
07626 cpl_vector_unwrap(ypos);
07627 cpl_vector_unwrap(xmpos);
07628 cpl_vector_unwrap(ympos);
07629 if (ypoly == NULL) {
07630 if (found_slits == nmaskslits) {
07631 cpl_msg_warning(func, "Fit failure: the accuracy of the "
07632 "identified slits positions is not improved.");
07633
07634
07635
07636
07637
07638
07639
07640
07641
07642 } else {
07643 cpl_msg_info(func, "Fit failure: not all slits have been "
07644 "identified. Process will continue using "
07645 "the detected CCD slits positions");
07646 }
07647
07648 cpl_polynomial_delete(xpoly);
07649 return positions;
07650 }
07651
07652 cpl_msg_info(func, "Fit successful: X rms = %.3g, Y rms = %.3g (pixel)",
07653 sqrt(xmse), sqrt(ymse));
07654
07655 if (global) {
07656 write_global_distortion(global, 0, xpoly);
07657 write_global_distortion(global, 7, ypoly);
07658 }
07659
07660
07661
07662
07663
07664
07665 cpl_table_delete(positions);
07666
07667 positions = cpl_table_duplicate(maskslits);
07668 cpl_table_duplicate_column(positions, "xmtop", positions, "xtop");
07669 cpl_table_duplicate_column(positions, "ymtop", positions, "ytop");
07670 cpl_table_duplicate_column(positions, "xmbottom", positions, "xbottom");
07671 cpl_table_duplicate_column(positions, "ymbottom", positions, "ybottom");
07672
07673 point = cpl_vector_new(2);
07674 dpoint = cpl_vector_get_data(point);
07675
07676 for (i = 0; i < nmaskslits; i++) {
07677 dpoint[0] = cpl_table_get_double(positions, "xmtop", i, NULL);
07678 dpoint[1] = cpl_table_get_double(positions, "ymtop", i, NULL);
07679 cpl_table_set_double(positions, "xtop", i,
07680 cpl_polynomial_eval(xpoly, point));
07681 cpl_table_set_double(positions, "ytop", i,
07682 cpl_polynomial_eval(ypoly, point));
07683 dpoint[0] = cpl_table_get_double(positions, "xmbottom", i, NULL);
07684 dpoint[1] = cpl_table_get_double(positions, "ymbottom", i, NULL);
07685 cpl_table_set_double(positions, "xbottom", i,
07686 cpl_polynomial_eval(xpoly, point));
07687 cpl_table_set_double(positions, "ybottom", i,
07688 cpl_polynomial_eval(ypoly, point));
07689 }
07690
07691 cpl_vector_delete(point);
07692 cpl_polynomial_delete(xpoly);
07693 cpl_polynomial_delete(ypoly);
07694
07695 cpl_table_erase_column(positions, "xmtop");
07696 cpl_table_erase_column(positions, "ymtop");
07697 cpl_table_erase_column(positions, "xmbottom");
07698 cpl_table_erase_column(positions, "ymbottom");
07699
07700 if (nmaskslits > nslits)
07701 cpl_msg_info(func, "Finally identified slits: %d out of %d expected\n"
07702 "(%d recovered)", nmaskslits, nmaskslits, nmaskslits - nslits);
07703 else if (nmaskslits < nslits)
07704 cpl_msg_info(func, "Finally identified slits: %d out of %d expected\n"
07705 "(%d rejected)", nmaskslits, nmaskslits, nslits - nmaskslits);
07706 else
07707 cpl_msg_info(func, "Finally identified slits: %d out of %d expected",
07708 nmaskslits, nmaskslits);
07709
07710 return positions;
07711 }
07712
07713
07755 cpl_table *mos_trace_flat(cpl_image *flat, cpl_table *slits, double reference,
07756 double blue, double red, double dispersion)
07757 {
07758
07759 const char *func = "mos_trace_flat";
07760
07761 cpl_image *gradient;
07762 cpl_image *sgradient;
07763 float *dgradient;
07764 float level = 500;
07765 cpl_vector *row;
07766 cpl_vector *srow;
07767 cpl_vector **peaks;
07768 double *peak;
07769 int *slit_id;
07770 float *g;
07771 double *r;
07772 double *xtop;
07773 double *ytop;
07774 double *xbottom;
07775 double *ybottom;
07776 double min, dist;
07777 double sradius;
07778 double tolerance;
07779 double start_y, prev_y;
07780 int minpos;
07781 int nslits;
07782 int nrows;
07783 int step = 10;
07784 int filtbox = 15;
07785 int nx, ny, npix;
07786 int pos, ypos;
07787 int npeaks;
07788 int pixel_above, pixel_below;
07789 int i, j, k, l;
07790 char trace_id[MAX_COLNAME];
07791
07792 cpl_table *traces;
07793
07794
07795 if (flat == NULL || slits == NULL) {
07796 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
07797 return NULL;
07798 }
07799
07800 if (dispersion <= 0.0) {
07801 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07802 return NULL;
07803 }
07804
07805 if (red - blue < dispersion) {
07806 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
07807 return NULL;
07808 }
07809
07810
07811
07812
07813
07814
07815 nslits = cpl_table_get_nrow(slits);
07816 if (1 != cpl_table_has_column(slits, "slit_id")) {
07817 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
07818 for (i = 0; i < nslits; i++)
07819 cpl_table_set_int(slits, "slit_id", i, -(i+1));
07820 }
07821
07822 slit_id = cpl_table_get_data_int(slits, "slit_id");
07823
07824 nx = cpl_image_get_size_x(flat);
07825 ny = cpl_image_get_size_y(flat);
07826 npix = nx * ny;
07827
07828 gradient = cpl_image_duplicate(flat);
07829 dgradient = cpl_image_get_data_float(gradient);
07830
07831 for (i = 0; i < ny - 1; i++) {
07832 k = i * nx;
07833 for (j = 0; j < nx; j++) {
07834 l = k + j;
07835 dgradient[l] = fabs(dgradient[l] - dgradient[l + nx]);
07836 }
07837 }
07838
07839 npix--;
07840 for (j = 0; j < nx; j++)
07841 dgradient[npix - j] = 0.0;
07842
07843 cpl_image_turn(gradient, -1);
07844 nx = cpl_image_get_size_x(gradient);
07845 ny = cpl_image_get_size_y(gradient);
07846 sgradient = mos_image_vertical_median_filter(gradient,
07847 filtbox, 0, ny, 0, step);
07848 cpl_image_delete(gradient);
07849
07850
07851
07852
07853
07854
07855 dgradient = cpl_image_get_data_float(sgradient);
07856
07857 for (i = 1; i <= ny; i += step) {
07858 row = cpl_vector_new_from_image_row(sgradient, i);
07859 srow = cpl_vector_filter_median_create(row, filtbox);
07860 cpl_vector_subtract(row, srow);
07861 cpl_vector_delete(srow);
07862 g = dgradient + (i-1)*nx;
07863 r = cpl_vector_get_data(row);
07864 for (j = 0; j < nx; j++)
07865 g[j] = r[j];
07866 cpl_vector_delete(row);
07867 }
07868
07869
07870
07871
07872
07873
07874
07875 mos_rotate_slits(slits, 1, nx, ny);
07876 xtop = cpl_table_get_data_double(slits, "xtop");
07877 ytop = cpl_table_get_data_double(slits, "ytop");
07878 xbottom = cpl_table_get_data_double(slits, "xbottom");
07879 ybottom = cpl_table_get_data_double(slits, "ybottom");
07880
07881
07882
07883
07884
07885
07886
07887 peaks = cpl_calloc(ny, sizeof(cpl_vector *));
07888
07889 for (i = 0; i < ny; i += step) {
07890 g = dgradient + i*nx;
07891 peaks[i] = mos_peak_candidates(g, nx, level, 1.0);
07892
07893
07894
07895 if (peaks[i])
07896 cpl_vector_subtract_scalar(peaks[i], 0.5);
07897
07898 }
07899
07900 cpl_image_delete(sgradient);
07901
07902
07903
07904
07905
07906
07907
07908
07909
07910 sradius = 5.0;
07911
07912
07913
07914
07915
07916
07917
07918
07919 tolerance = 0.9;
07920
07921
07922
07923
07924
07925
07926 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
07927 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
07928
07929
07930
07931
07932
07933
07934 nrows = (ny-1)/step + 1;
07935 traces = cpl_table_new(nrows);
07936 cpl_table_new_column(traces, "x", CPL_TYPE_DOUBLE);
07937 cpl_table_set_column_unit(traces, "x", "pixel");
07938 for (i = 0, j = 0; i < ny; i += step, j++)
07939 cpl_table_set(traces, "x", j, i);
07940
07941 for (i = 0; i < nslits; i++) {
07942
07943
07944
07945
07946
07947 ypos = ytop[i];
07948
07949 if (ypos < 0)
07950 ypos = 0;
07951 if (ypos >= ny)
07952 ypos = ny - 1;
07953
07954 pos = ypos / step;
07955 pos *= step;
07956
07957
07958
07959
07960
07961 if (peaks[pos]) {
07962 peak = cpl_vector_get_data(peaks[pos]);
07963 npeaks = cpl_vector_get_size(peaks[pos]);
07964
07965 min = fabs(peak[0] - xtop[i]);
07966 minpos = 0;
07967 for (j = 1; j < npeaks; j++) {
07968 dist = fabs(peak[j] - xtop[i]);
07969 if (min > dist) {
07970 min = dist;
07971 minpos = j;
07972 }
07973 }
07974 }
07975 else {
07976 npeaks = 0;
07977 }
07978
07979 snprintf(trace_id, MAX_COLNAME, "t%d", slit_id[i]);
07980 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
07981
07982 if (min > sradius || npeaks == 0) {
07983 cpl_msg_warning(func, "Cannot find spectrum edge for "
07984 "top (or left) end of slit %d", slit_id[i]);
07985 }
07986 else {
07987
07988
07989
07990
07991
07992
07993
07994
07995
07996 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
07997 start_y = peak[minpos];
07998
07999
08000
08001
08002
08003 prev_y = start_y;
08004
08005 for (j = pos + step; j < ny; j += step) {
08006 if (j - pos > pixel_above)
08007 break;
08008 if (peaks[j]) {
08009 peak = cpl_vector_get_data(peaks[j]);
08010 npeaks = cpl_vector_get_size(peaks[j]);
08011 min = fabs(peak[0] - prev_y);
08012 minpos = 0;
08013 for (k = 1; k < npeaks; k++) {
08014 dist = fabs(peak[k] - prev_y);
08015 if (min > dist) {
08016 min = dist;
08017 minpos = k;
08018 }
08019 }
08020 if (min < tolerance) {
08021 cpl_table_set(traces, trace_id, j/step,
08022 nx - peak[minpos]);
08023 prev_y = peak[minpos];
08024 }
08025 }
08026 }
08027
08028
08029
08030
08031
08032 prev_y = start_y;
08033
08034 for (j = pos - step; j >= 0; j -= step) {
08035 if (pos - j > pixel_below)
08036 break;
08037 if (peaks[j]) {
08038 peak = cpl_vector_get_data(peaks[j]);
08039 npeaks = cpl_vector_get_size(peaks[j]);
08040 min = fabs(peak[0] - prev_y);
08041 minpos = 0;
08042 for (k = 1; k < npeaks; k++) {
08043 dist = fabs(peak[k] - prev_y);
08044 if (min > dist) {
08045 min = dist;
08046 minpos = k;
08047 }
08048 }
08049 if (min < tolerance) {
08050 cpl_table_set(traces, trace_id, j/step,
08051 nx - peak[minpos]);
08052 prev_y = peak[minpos];
08053 }
08054 }
08055 }
08056 }
08057
08058
08059
08060
08061
08062
08063 if (peaks[pos]) {
08064 peak = cpl_vector_get_data(peaks[pos]);
08065 npeaks = cpl_vector_get_size(peaks[pos]);
08066
08067 min = fabs(peak[0] - xbottom[i]);
08068 minpos = 0;
08069 for (j = 1; j < npeaks; j++) {
08070 dist = fabs(peak[j] - xbottom[i]);
08071 if (min > dist) {
08072 min = dist;
08073 minpos = j;
08074 }
08075 }
08076 }
08077 else {
08078 npeaks = 0;
08079 }
08080
08081 snprintf(trace_id, MAX_COLNAME, "b%d", slit_id[i]);
08082 cpl_table_new_column(traces, trace_id, CPL_TYPE_DOUBLE);
08083
08084 if (min > sradius || npeaks == 0) {
08085 cpl_msg_warning(func, "Cannot find spectrum edge for "
08086 "bottom (or right) end of slit %d", slit_id[i]);
08087 }
08088 else {
08089
08090 cpl_table_set(traces, trace_id, pos/step, nx - peak[minpos]);
08091 start_y = peak[minpos];
08092
08093
08094
08095
08096
08097 prev_y = start_y;
08098
08099 for (j = pos + step; j < ny; j += step) {
08100 if (j - pos > pixel_above)
08101 break;
08102 if (peaks[j]) {
08103 peak = cpl_vector_get_data(peaks[j]);
08104 npeaks = cpl_vector_get_size(peaks[j]);
08105 min = fabs(peak[0] - prev_y);
08106 minpos = 0;
08107 for (k = 1; k < npeaks; k++) {
08108 dist = fabs(peak[k] - prev_y);
08109 if (min > dist) {
08110 min = dist;
08111 minpos = k;
08112 }
08113 }
08114 if (min < tolerance) {
08115 cpl_table_set(traces, trace_id, j/step,
08116 nx - peak[minpos]);
08117 prev_y = peak[minpos];
08118 }
08119 }
08120 }
08121
08122
08123
08124
08125
08126 prev_y = start_y;
08127
08128 for (j = pos - step; j >= 0; j -= step) {
08129 if (pos - j > pixel_below)
08130 break;
08131 if (peaks[j]) {
08132 peak = cpl_vector_get_data(peaks[j]);
08133 npeaks = cpl_vector_get_size(peaks[j]);
08134 min = fabs(peak[0] - prev_y);
08135 minpos = 0;
08136 for (k = 1; k < npeaks; k++) {
08137 dist = fabs(peak[k] - prev_y);
08138 if (min > dist) {
08139 min = dist;
08140 minpos = k;
08141 }
08142 }
08143 if (min < tolerance) {
08144 cpl_table_set(traces, trace_id, j/step,
08145 nx - peak[minpos]);
08146 prev_y = peak[minpos];
08147 }
08148 }
08149 }
08150 }
08151
08152 }
08153
08154 for (i = 0; i < ny; i += step)
08155 cpl_vector_delete(peaks[i]);
08156 cpl_free(peaks);
08157
08158
08159
08160
08161
08162 mos_rotate_slits(slits, -1, ny, nx);
08163
08164 return traces;
08165
08166 }
08167
08168
08189 cpl_table *mos_poly_trace(cpl_table *slits, cpl_table *traces, int order)
08190 {
08191 const char *func = "mos_poly_trace";
08192
08193 cpl_table *polytraces;
08194 cpl_table *dummy;
08195 cpl_vector *x;
08196 cpl_vector *trace;
08197 cpl_polynomial *polytrace;
08198 char trace_id[MAX_COLNAME];
08199 char trace_res[MAX_COLNAME];
08200 char trace_mod[MAX_COLNAME];
08201 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
08202
08203 double *xdata;
08204 int *slit_id;
08205 int nslits;
08206 int nrows;
08207 int npoints;
08208 int i, j;
08209 cpl_size k;
08210
08211
08212 if (traces == NULL || slits == NULL) {
08213 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08214 return NULL;
08215 }
08216
08217 if (order > 5) {
08218 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08219 return NULL;
08220 }
08221
08222 nrows = cpl_table_get_nrow(traces);
08223 xdata = cpl_table_get_data_double(traces, "x");
08224 nslits = cpl_table_get_nrow(slits);
08225 slit_id = cpl_table_get_data_int(slits, "slit_id");
08226
08227 polytraces = cpl_table_new(2*nslits);
08228 cpl_table_new_column(polytraces, "slit_id", CPL_TYPE_INT);
08229 for (i = 0; i <= order; i++)
08230 cpl_table_new_column(polytraces, clab[i], CPL_TYPE_DOUBLE);
08231
08232 for (i = 0; i < nslits; i++) {
08233 for (j = 0; j < 2; j++) {
08234
08235 if (j) {
08236 snprintf(trace_id, MAX_COLNAME, "b%d", slit_id[i]);
08237 snprintf(trace_res, MAX_COLNAME, "b%d_res", slit_id[i]);
08238 snprintf(trace_mod, MAX_COLNAME, "b%d_mod", slit_id[i]);
08239 }
08240 else {
08241 snprintf(trace_id, MAX_COLNAME, "t%d", slit_id[i]);
08242 snprintf(trace_res, MAX_COLNAME, "t%d_res", slit_id[i]);
08243 snprintf(trace_mod, MAX_COLNAME, "t%d_mod", slit_id[i]);
08244 }
08245
08246 cpl_table_set_int(polytraces, "slit_id", 2*i+j, slit_id[i]);
08247
08248
08249
08250
08251
08252
08253 dummy = cpl_table_new(nrows);
08254 cpl_table_duplicate_column(dummy, "x", traces, "x");
08255 cpl_table_duplicate_column(dummy, trace_id, traces, trace_id);
08256 npoints = nrows - cpl_table_count_invalid(dummy, trace_id);
08257 if (npoints < 2 * order) {
08258 cpl_table_delete(dummy);
08259 continue;
08260 }
08261 cpl_table_erase_invalid(dummy);
08262 x = cpl_vector_wrap(npoints,
08263 cpl_table_get_data_double(dummy, "x"));
08264 trace = cpl_vector_wrap(npoints,
08265 cpl_table_get_data_double(dummy, trace_id));
08266 polytrace = cpl_polynomial_fit_1d_create(x, trace, order, NULL);
08267 cpl_vector_unwrap(x);
08268 cpl_vector_unwrap(trace);
08269 cpl_table_delete(dummy);
08270
08271
08272
08273
08274
08275
08276
08277 k = 2;
08278 if (fabs(cpl_polynomial_get_coeff(polytrace, &k)) > 1.E-4) {
08279 cpl_polynomial_delete(polytrace);
08280 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
08281 cpl_table_duplicate_column(traces, trace_res, traces,
08282 trace_mod);
08283 if (j)
08284 cpl_msg_warning(func, "Exclude bad curvature solution "
08285 "for bottom (right) edge of slit %d", slit_id[i]);
08286 else
08287 cpl_msg_warning(func, "Exclude bad curvature solution "
08288 "for top (left) edge of slit %d", slit_id[i]);
08289 continue;
08290 }
08291
08292
08293
08294
08295
08296
08297 for (k = 0; k <= order; k++)
08298 cpl_table_set_double(polytraces, clab[k], 2*i+j,
08299 cpl_polynomial_get_coeff(polytrace, &k));
08300
08301
08302
08303
08304
08305 cpl_table_new_column(traces, trace_mod, CPL_TYPE_DOUBLE);
08306 cpl_table_set_column_unit(traces, trace_mod, "pixel");
08307
08308 for (k = 0; k < nrows; k++) {
08309 cpl_table_set_double(traces, trace_mod, k,
08310 cpl_polynomial_eval_1d(polytrace, xdata[k], NULL));
08311 }
08312
08313 cpl_polynomial_delete(polytrace);
08314
08315 cpl_table_duplicate_column(traces, trace_res, traces, trace_mod);
08316 cpl_table_subtract_columns(traces, trace_res, trace_id);
08317 cpl_table_multiply_scalar(traces, trace_res, -1.0);
08318
08319 }
08320 }
08321
08322 return polytraces;
08323
08324 }
08325
08326
08350 cpl_error_code mos_global_trace(cpl_table *slits, cpl_table *polytraces,
08351 int mode)
08352 {
08353 const char *func = "mos_global_trace";
08354
08355 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
08356
08357 cpl_table *table;
08358 cpl_vector *c0;
08359 cpl_vector *cn;
08360 cpl_bivector *list;
08361
08362
08363
08364
08365 double *offset;
08366 double rms, q, m;
08367
08368 int order, nrows, nslits;
08369 int i, j;
08370
08371
08372 if (polytraces == NULL) {
08373 cpl_msg_error(func, "Missing spectral curvature table");
08374 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08375 }
08376
08377 if (slits == NULL) {
08378 cpl_msg_error(func, "Missing slits positions table");
08379 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08380 }
08381
08382 nslits = cpl_table_get_nrow(slits);
08383
08384 table = cpl_table_duplicate(polytraces);
08385 cpl_table_erase_invalid(table);
08386
08387 nrows = cpl_table_get_nrow(table);
08388
08389 if (nrows < 4) {
08390 cpl_msg_warning(func, "Too few successful spectral curvature tracings "
08391 "(%d): the determination of a global curvature model "
08392 "failed", nrows);
08393 return CPL_ERROR_NONE;
08394 }
08395
08396 order = cpl_table_get_ncol(polytraces) - 2;
08397
08398 for (i = 0; i <= order; i++) {
08399 if (!cpl_table_has_column(table, clab[i])) {
08400 cpl_msg_error(func, "Wrong spectral curvature table");
08401 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08402 }
08403 }
08404
08405
08406
08407
08408
08409
08410 for (i = 0; i < nslits; i++) {
08411 if (!cpl_table_is_valid(polytraces, clab[0], 2*i)) {
08412 cpl_table_set_double(polytraces, clab[0], 2*i,
08413 cpl_table_get_double(slits, "ytop", i, NULL));
08414 }
08415 if (!cpl_table_is_valid(polytraces, clab[0], 2*i+1)) {
08416 cpl_table_set_double(polytraces, clab[0], 2*i+1,
08417 cpl_table_get_double(slits, "ybottom", i, NULL));
08418 }
08419 }
08420
08421 offset = cpl_table_get_data_double(polytraces, clab[0]);
08422
08423
08424
08425
08426
08427
08428 c0 = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[0]));
08429
08430 for (i = 1; i <= order; i++) {
08431 cn = cpl_vector_wrap(nrows, cpl_table_get_data_double(table, clab[i]));
08432 list = cpl_bivector_wrap_vectors(c0, cn);
08433 robustLinearFit(list, &q, &m, &rms);
08434
08435
08436
08437 for (j = 0; j < 2*nslits; j++) {
08438 if (mode == 1)
08439 if (cpl_table_is_valid(polytraces, clab[i], j))
08440 continue;
08441 cpl_table_set_double(polytraces, clab[i], j, offset[j]*m + q);
08442
08443
08444
08445
08446 }
08447 cpl_bivector_unwrap_vectors(list);
08448
08449
08450
08451 cpl_vector_unwrap(cn);
08452 }
08453
08454 cpl_vector_unwrap(c0);
08455 cpl_table_delete(table);
08456
08457 return CPL_ERROR_NONE;
08458
08459 }
08460
08461
08531 cpl_image *mos_spatial_calibration(cpl_image *spectra, cpl_table *slits,
08532 cpl_table *polytraces, double reference,
08533 double blue, double red, double dispersion,
08534 int flux, cpl_image *calibration)
08535 {
08536 const char *func = "mos_spatial_calibration";
08537
08538 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
08539
08540 cpl_polynomial *polytop;
08541 cpl_polynomial *polybot;
08542 cpl_image **exslit;
08543 cpl_image *resampled;
08544 float *data;
08545 float *sdata;
08546 float *xdata;
08547 double vtop, vbot, value;
08548 double top, bot;
08549 double coeff;
08550 double ytop, ybot;
08551 double ypos, yfra;
08552 double factor;
08553 int yint, ysize, yprev;
08554 int nslits;
08555 int npseudo;
08556 int *slit_id;
08557 int *length;
08558 int nx, ny;
08559 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
08560 int missing_top, missing_bot;
08561 int null;
08562 int order;
08563 int i, j;
08564 cpl_size k;
08565
08566 int create_position = 1;
08567
08568
08569 if (spectra == NULL || slits == NULL || polytraces == NULL) {
08570 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
08571 return NULL;
08572 }
08573
08574 if (dispersion <= 0.0) {
08575 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08576 return NULL;
08577 }
08578
08579 if (red - blue < dispersion) {
08580 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
08581 return NULL;
08582 }
08583
08584 nx = cpl_image_get_size_x(spectra);
08585 ny = cpl_image_get_size_y(spectra);
08586 sdata = cpl_image_get_data(spectra);
08587 if (calibration)
08588 data = cpl_image_get_data(calibration);
08589
08590 if (cpl_table_has_column(slits, "position"))
08591 create_position = 0;
08592
08593 if (create_position) {
08594 cpl_table_new_column(slits, "position", CPL_TYPE_INT);
08595 cpl_table_new_column(slits, "length", CPL_TYPE_INT);
08596 cpl_table_set_column_unit(slits, "position", "pixel");
08597 cpl_table_set_column_unit(slits, "length", "pixel");
08598 }
08599 else
08600 length = cpl_table_get_data_int(slits, "length");
08601
08602 nslits = cpl_table_get_nrow(slits);
08603 slit_id = cpl_table_get_data_int(slits, "slit_id");
08604 order = cpl_table_get_ncol(polytraces) - 2;
08605
08606
08607
08608
08609
08610
08611 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
08612 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
08613
08614 exslit = cpl_calloc(nslits, sizeof(cpl_image *));
08615
08616 for (i = 0; i < nslits; i++) {
08617
08618 if (create_position == 0)
08619 if (length[i] == 0)
08620 continue;
08621
08622
08623
08624
08625
08626
08627
08628
08629
08630
08631
08632
08633 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
08634
08635 start_pixel = refpixel - pixel_below;
08636 if (start_pixel < 0)
08637 start_pixel = 0;
08638
08639 end_pixel = refpixel + pixel_above;
08640 if (end_pixel > nx)
08641 end_pixel = nx;
08642
08643
08644
08645
08646
08647
08648 missing_top = 0;
08649 polytop = cpl_polynomial_new(1);
08650 for (k = 0; k <= order; k++) {
08651 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
08652 if (null) {
08653 cpl_polynomial_delete(polytop);
08654 missing_top = 1;
08655 break;
08656 }
08657 cpl_polynomial_set_coeff(polytop, &k, coeff);
08658 }
08659
08660 missing_bot = 0;
08661 polybot = cpl_polynomial_new(1);
08662 for (k = 0; k <= order; k++) {
08663 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
08664 if (null) {
08665 cpl_polynomial_delete(polybot);
08666 missing_bot = 1;
08667 break;
08668 }
08669 cpl_polynomial_set_coeff(polybot, &k, coeff);
08670 }
08671
08672 if (missing_top && missing_bot) {
08673 cpl_msg_warning(func, "Spatial calibration, slit %d was not "
08674 "traced: no extraction!",
08675 slit_id[i]);
08676 continue;
08677 }
08678
08679
08680
08681
08682
08683
08684
08685 if (missing_top) {
08686 cpl_msg_warning(func, "Upper edge of slit %d was not traced: "
08687 "the spectral curvature of the lower edge "
08688 "is used instead.", slit_id[i]);
08689 polytop = cpl_polynomial_duplicate(polybot);
08690 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
08691 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
08692 k = 0;
08693 coeff = cpl_polynomial_get_coeff(polybot, &k);
08694 coeff += ytop - ybot;
08695 cpl_polynomial_set_coeff(polytop, &k, coeff);
08696 }
08697
08698 if (missing_bot) {
08699 cpl_msg_warning(func, "Lower edge of slit %d was not traced: "
08700 "the spectral curvature of the upper edge "
08701 "is used instead.", slit_id[i]);
08702 polybot = cpl_polynomial_duplicate(polytop);
08703 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
08704 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
08705 k = 0;
08706 coeff = cpl_polynomial_get_coeff(polytop, &k);
08707 coeff -= ytop - ybot;
08708 cpl_polynomial_set_coeff(polybot, &k, coeff);
08709 }
08710
08711
08712
08713
08714
08715 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
08716 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
08717 npseudo = ceil(top-bot) + 1;
08718
08719 if (npseudo < 1) {
08720 cpl_polynomial_delete(polytop);
08721 cpl_polynomial_delete(polybot);
08722 cpl_msg_warning(func, "Slit %d was badly traced: no extraction!",
08723 slit_id[i]);
08724 continue;
08725 }
08726
08727 exslit[i] = cpl_image_new(nx, npseudo+1, CPL_TYPE_FLOAT);
08728 xdata = cpl_image_get_data(exslit[i]);
08729
08730
08731
08732
08733
08734 for (j = start_pixel; j < end_pixel; j++) {
08735 top = cpl_polynomial_eval_1d(polytop, j, NULL);
08736 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
08737 factor = (top-bot)/npseudo;
08738 for (k = 0; k <= npseudo; k++) {
08739 ypos = top - k*factor;
08740 yint = floor(ypos);
08741 yfra = ypos - yint;
08742 if (yint >= 0 && yint < ny-1) {
08743 vtop = sdata[j + nx*yint];
08744 vbot = sdata[j + nx*(yint+1)];
08745
08746
08747
08748 if(factor <= 0 )
08749 value = 0;
08750 else if(vtop == FLT_MAX || vbot == FLT_MAX)
08751 value = FLT_MAX;
08752 else
08753 {
08754 value = vtop*(1-yfra) + vbot*yfra;
08755 if (flux)
08756 value *= factor;
08757 }
08758 xdata[j + nx*(npseudo-k)] = value;
08759 if (calibration) {
08760 data[j + nx*yint] = (top-yint)/factor;
08761 if (k) {
08762
08763
08764
08765
08766
08767
08768
08769 if (yprev - yint > 1) {
08770 data[j + nx*(yint+1)] = (top-yint-1)/factor;
08771 }
08772 }
08773 }
08774 }
08775 yprev = yint;
08776 }
08777 }
08778 cpl_polynomial_delete(polytop);
08779 cpl_polynomial_delete(polybot);
08780 }
08781
08782
08783
08784
08785
08786 ysize = 0;
08787 for (i = 0; i < nslits; i++)
08788 if (exslit[i])
08789 ysize += cpl_image_get_size_y(exslit[i]);
08790
08791 if(ysize == 0)
08792 return NULL;
08793
08794 resampled = cpl_image_new(nx, ysize, CPL_TYPE_FLOAT);
08795
08796 yint = -1;
08797 for (i = 0; i < nslits; i++) {
08798 if (exslit[i]) {
08799 yint += cpl_image_get_size_y(exslit[i]);
08800 cpl_image_copy(resampled, exslit[i], 1, ysize - yint);
08801 if (create_position) {
08802 cpl_table_set_int(slits, "position", i, ysize - yint - 1);
08803 cpl_table_set_int(slits, "length", i,
08804 cpl_image_get_size_y(exslit[i]));
08805 }
08806 cpl_image_delete(exslit[i]);
08807 }
08808 else if (create_position) {
08809 cpl_table_set_int(slits, "position", i, -1);
08810 cpl_table_set_int(slits, "length", i, 0);
08811 }
08812 }
08813
08814
08815
08816
08817
08818
08819
08820
08821
08822
08823
08824
08825
08826
08827
08828
08829
08830 cpl_free(exslit);
08831
08832 return resampled;
08833
08834 }
08835
08836
08949 cpl_image *mos_wavelength_calibration_final(cpl_image *image, cpl_table *slits,
08950 cpl_vector *lines,
08951 double dispersion, float level,
08952 int sradius, int order,
08953 double reject, double refwave,
08954 double *wavestart, double *waveend,
08955 int *nlines, double *error,
08956 cpl_table *idscoeff,
08957 cpl_image *calibration,
08958 cpl_image *residuals,
08959 cpl_table *restable,
08960 cpl_table *detected_lines)
08961 {
08962
08963 const char *func = "mos_wavelength_calibration_final";
08964
08965 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
08966
08967
08968 double tolerance = 20.0;
08969 int step = 10;
08970
08971 char name[MAX_COLNAME];
08972
08973 cpl_image *resampled;
08974 cpl_bivector *peaks_ident;
08975 cpl_vector *wavel;
08976 cpl_vector *peaks;
08977 cpl_polynomial *ids;
08978 cpl_polynomial *lin;
08979 cpl_polynomial *fguess;
08980 cpl_table *coeff;
08981 double ids_err;
08982 double max_disp, min_disp;
08983 double *line;
08984 double firstLambda, lastLambda, lambda;
08985 double wave, pixe, value;
08986 double c;
08987 float *sdata;
08988 float *rdata;
08989 float *idata;
08990 float *ddata;
08991 float v1, v2, vi;
08992 float fpixel;
08993 int *length;
08994 int pixstart, pixend;
08995 int row_top, row_bot;
08996 int extrapolation;
08997 int nref;
08998 int nslits;
08999 int nfits;
09000 int nl, nx, ny, pixel;
09001 int countLines, usedLines;
09002 int uorder;
09003 int missing;
09004 int null;
09005 int width, uradius;
09006 int i, j, s;
09007 cpl_size k;
09008
09009
09010 if (dispersion == 0.0) {
09011 cpl_msg_error(func, "The expected dispersion (A/pixel) must be given");
09012 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
09013 return NULL;
09014 }
09015
09016 if (dispersion < 0.0) {
09017 cpl_msg_error(func, "The expected dispersion must be positive");
09018 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
09019 return NULL;
09020 }
09021
09022 if (idscoeff == NULL) {
09023 cpl_msg_error(func, "A preallocated IDS coeff table must be given");
09024 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09025 return NULL;
09026 }
09027
09028 max_disp = dispersion + dispersion * tolerance / 100;
09029 min_disp = dispersion - dispersion * tolerance / 100;
09030
09031 if (order < 1) {
09032 cpl_msg_error(func, "The order of the fitting polynomial "
09033 "must be at least 1");
09034 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
09035 return NULL;
09036 }
09037
09038 if (image == NULL || lines == NULL) {
09039 cpl_msg_error(func, "Both spectral exposure and reference line "
09040 "catalog are required in input");
09041 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09042 return NULL;
09043 }
09044
09045 nx = cpl_image_get_size_x(image);
09046 ny = cpl_image_get_size_y(image);
09047 sdata = cpl_image_get_data_float(image);
09048
09049 nref = cpl_vector_get_size(lines);
09050 line = cpl_vector_get_data(lines);
09051
09052 if (*wavestart < 1.0 && *waveend < 1.0) {
09053 firstLambda = line[0];
09054 lastLambda = line[nref-1];
09055 extrapolation = (lastLambda - firstLambda) / 10;
09056 firstLambda -= extrapolation;
09057 lastLambda += extrapolation;
09058 *wavestart = firstLambda;
09059 *waveend = lastLambda;
09060 }
09061 else {
09062 firstLambda = *wavestart;
09063 lastLambda = *waveend;
09064 }
09065
09066 nl = (lastLambda - firstLambda) / dispersion;
09067 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
09068 rdata = cpl_image_get_data_float(resampled);
09069
09070
09071
09072
09073
09074 for (j = 0; j <= order; j++)
09075 cpl_table_new_column(idscoeff, clab[j], CPL_TYPE_DOUBLE);
09076
09077 if (calibration)
09078 idata = cpl_image_get_data_float(calibration);
09079
09080 if (residuals)
09081 ddata = cpl_image_get_data_float(residuals);
09082
09083 if (restable) {
09084 cpl_table_set_size(restable, nref);
09085 cpl_table_new_column(restable, "wavelength", CPL_TYPE_DOUBLE);
09086 cpl_table_copy_data_double(restable, "wavelength", line);
09087 for (i = 0; i < ny; i += step) {
09088 snprintf(name, MAX_COLNAME, "r%d", i);
09089 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
09090 snprintf(name, MAX_COLNAME, "d%d", i);
09091 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
09092 snprintf(name, MAX_COLNAME, "p%d", i);
09093 cpl_table_new_column(restable, name, CPL_TYPE_DOUBLE);
09094 }
09095 }
09096
09097 if (detected_lines) {
09098 cpl_table_set_size(detected_lines, 0);
09099 cpl_table_new_column(detected_lines, "slit_id", CPL_TYPE_INT);
09100 cpl_table_new_column(detected_lines, "xpos_rectified", CPL_TYPE_DOUBLE);
09101 cpl_table_new_column(detected_lines, "ypos_rectified", CPL_TYPE_DOUBLE);
09102 cpl_table_new_column(detected_lines, "xpos_rectified_iter", CPL_TYPE_DOUBLE);
09103 cpl_table_new_column(detected_lines, "ypos_rectified_iter", CPL_TYPE_DOUBLE);
09104 cpl_table_new_column(detected_lines, "peak_flux", CPL_TYPE_DOUBLE);
09105 cpl_table_new_column(detected_lines, "wave_ident", CPL_TYPE_DOUBLE);
09106 cpl_table_new_column(detected_lines, "wave_ident_iter", CPL_TYPE_DOUBLE);
09107 cpl_table_new_column(detected_lines, "xpos_fit_rect_wavecal", CPL_TYPE_DOUBLE);
09108 cpl_table_new_column(detected_lines, "res_xpos", CPL_TYPE_DOUBLE);
09109 cpl_table_new_column(detected_lines, "fit_used", CPL_TYPE_INT);
09110 }
09111
09112
09113
09114
09115
09116
09117 nslits = cpl_table_get_nrow(slits);
09118 length = cpl_table_get_data_int(slits, "length");
09119
09120 row_top = ny;
09121 for (s = 0; s < nslits; s++) {
09122
09123 int slit_id;
09124 slit_id = cpl_table_get_int(slits, "slit_id", s, NULL);
09125
09126 if (length[s] == 0)
09127 continue;
09128
09129
09130
09131
09132
09133
09134 row_bot = cpl_table_get_int(slits, "position", s, NULL);
09135
09136 if (sradius > 0) {
09137
09138
09139
09140
09141
09142
09143
09144
09145
09146 coeff = cpl_table_new(row_top - row_bot);
09147 for (j = 0; j <= order; j++)
09148 cpl_table_new_column(coeff, clab[j], CPL_TYPE_DOUBLE);
09149 }
09150
09151
09152
09153
09154
09155
09156 for (i = row_bot; i < row_top; i++) {
09157 width = mos_lines_width(sdata + i*nx, nx);
09158 if (width < 5)
09159 width = 5;
09160 peaks = mos_peak_candidates(sdata + i*nx, nx, level, width);
09161 if (peaks) {
09162 peaks = mos_refine_peaks(sdata + i*nx, nx, peaks, width);
09163 }
09164 if (peaks) {
09165 int keep_multiplex = mos_multiplex;
09166 mos_multiplex = -1;
09167 if(detected_lines)
09168 {
09169 cpl_size newlines = cpl_vector_get_size(peaks);
09170 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
09171 cpl_table_set_size(detected_lines, oldsize + newlines);
09172 for(cpl_size iline = 0; iline < newlines; ++iline)
09173 {
09174 cpl_table_set_int(detected_lines, "slit_id",
09175 oldsize + iline, slit_id);
09176 cpl_table_set_double(detected_lines, "xpos_rectified",
09177 oldsize + iline, cpl_vector_get(peaks, iline) + 1);
09178 cpl_table_set_double(detected_lines, "ypos_rectified",
09179 oldsize + iline, (double)i + 1);
09180 cpl_table_set_double(detected_lines, "peak_flux",
09181 oldsize + iline,
09182 sdata[i*nx+(int)(cpl_vector_get(peaks, iline)+0.5)]);
09183 cpl_table_set_int(detected_lines,
09184 "fit_used",
09185 oldsize + iline, 0);
09186 }
09187 }
09188 peaks_ident = mos_identify_peaks(peaks, lines,
09189 min_disp, max_disp, 0.05);
09190 mos_multiplex = keep_multiplex;
09191 if (peaks_ident) {
09192 cpl_bivector * peaks_ident_used_fit;
09193 countLines = cpl_bivector_get_size(peaks_ident);
09194 if (countLines < 4) {
09195 cpl_bivector_delete(peaks_ident);
09196 cpl_vector_delete(peaks);
09197 if (nlines)
09198 nlines[i] = 0;
09199 if (error)
09200 error[i] = 0.0;
09201 continue;
09202 }
09203
09204
09205
09206
09207
09208 wavel = cpl_bivector_get_y(peaks_ident);
09209 cpl_vector_subtract_scalar(wavel, refwave);
09210
09211 uorder = countLines / 2 - 1;
09212 if (uorder > order)
09213 uorder = order;
09214
09215 ids = mos_poly_wav2pix(peaks_ident, uorder, reject,
09216 2 * (uorder + 1), &usedLines,
09217 &ids_err, &peaks_ident_used_fit);
09218
09219 if (ids == NULL) {
09220 cpl_bivector_delete(peaks_ident);
09221 cpl_vector_delete(peaks);
09222 if (nlines)
09223 nlines[i] = 0;
09224 if (error)
09225 error[i] = 0.0;
09226 cpl_error_reset();
09227 continue;
09228 }
09229
09230 if (sradius > 0) {
09231 for (k = 0; k <= order; k++) {
09232 if (k > uorder) {
09233 cpl_table_set_double(coeff, clab[k],
09234 i - row_bot, 0.0);
09235 }
09236 else {
09237 cpl_table_set_double(coeff, clab[k],
09238 i - row_bot, cpl_polynomial_get_coeff(ids, &k));
09239 }
09240 }
09241 }
09242
09243 if (calibration) {
09244 pixstart = cpl_polynomial_eval_1d(ids,
09245 cpl_bivector_get_y_data(peaks_ident)[0],
09246 NULL);
09247 pixend = cpl_polynomial_eval_1d(ids,
09248 cpl_bivector_get_y_data(peaks_ident)[countLines-1],
09249 NULL);
09250 extrapolation = (pixend - pixstart) / 5;
09251 pixstart -= extrapolation;
09252 pixend += extrapolation;
09253 if (pixstart < 0)
09254 pixstart = 0;
09255 if (pixend > nx)
09256 pixend = nx;
09257
09258 for (j = pixstart; j < pixend; j++) {
09259 (idata + i*nx)[j] = mos_eval_dds(ids,
09260 firstLambda, lastLambda, refwave, j);
09261 }
09262 }
09263
09264
09265
09266
09267
09268 if (residuals || (restable && !(i%step))) {
09269 if (restable && !(i%step)) {
09270 lin = cpl_polynomial_new(1);
09271 for (k = 0; k < 2; k++)
09272 cpl_polynomial_set_coeff(lin, &k,
09273 cpl_polynomial_get_coeff(ids, &k));
09274 }
09275 for (j = 0; j < countLines; j++) {
09276 pixe = cpl_bivector_get_x_data(peaks_ident)[j];
09277 wave = cpl_bivector_get_y_data(peaks_ident)[j];
09278 value = pixe
09279 - cpl_polynomial_eval_1d(ids, wave, NULL);
09280 if (residuals) {
09281 pixel = pixe + 0.5;
09282 (ddata + i*nx)[pixel] = value;
09283 }
09284 if (restable && !(i%step)) {
09285 for (k = 0; k < nref; k++) {
09286 if (fabs(line[k]-refwave-wave) < 0.1) {
09287 snprintf(name, MAX_COLNAME,
09288 "r%d", i);
09289 cpl_table_set_double(restable, name,
09290 k, value);
09291 value = pixe
09292 - cpl_polynomial_eval_1d(lin,
09293 wave, NULL);
09294 snprintf(name, MAX_COLNAME,
09295 "d%d", i);
09296 cpl_table_set_double(restable, name,
09297 k, value);
09298 snprintf(name, MAX_COLNAME,
09299 "p%d", i);
09300 cpl_table_set_double(restable, name,
09301 k, pixe);
09302 break;
09303 }
09304 }
09305 }
09306 }
09307 if (restable && !(i%step)) {
09308 cpl_polynomial_delete(lin);
09309 }
09310
09311
09312
09313
09314
09315
09316
09317
09318
09319
09320
09321
09322
09323 if(detected_lines)
09324 {
09325 cpl_size nidentlines = cpl_bivector_get_size(peaks_ident);
09326 cpl_size ndetectlines = cpl_vector_get_size(peaks);
09327 cpl_size totalsize = cpl_table_get_nrow(detected_lines);
09328 for(cpl_size idline = 0; idline < nidentlines; ++idline)
09329 {
09330 for(cpl_size detline = 0; detline < ndetectlines; ++detline)
09331 {
09332 if(cpl_vector_get(peaks, detline) ==
09333 cpl_bivector_get_x_data(peaks_ident)[idline])
09334 {
09335 cpl_size table_pos = totalsize - ndetectlines + detline;
09336 double wave_ident = cpl_bivector_get_y_data(peaks_ident)[idline] + refwave;
09337 double xpix_fit = cpl_polynomial_eval_1d(ids,
09338 wave_ident - refwave, NULL);
09339 double xpos_det = cpl_table_get_double(detected_lines,
09340 "xpos_rectified",
09341 table_pos, &null);
09342 cpl_table_set_double(detected_lines,
09343 "wave_ident",
09344 table_pos,
09345 wave_ident);
09346 cpl_table_set_double(detected_lines,
09347 "xpos_fit_rect_wavecal",
09348 table_pos,
09349 xpix_fit + 1);
09350 cpl_table_set_double(detected_lines,
09351 "res_xpos",
09352 table_pos,
09353 xpos_det - xpix_fit - 1);
09354 cpl_table_set_int(detected_lines,
09355 "fit_used",
09356 table_pos, 0);
09357 for(cpl_size i_used = 0; i_used < cpl_bivector_get_size(peaks_ident_used_fit); ++i_used)
09358 {
09359 if(cpl_bivector_get_x_data(peaks_ident)[idline] == cpl_bivector_get_x_data(peaks_ident_used_fit)[i_used])
09360 cpl_table_set_int(detected_lines,
09361 "fit_used",
09362 table_pos, 1);
09363 }
09364 }
09365 }
09366 }
09367 }
09368
09369 }
09370
09371
09372
09373
09374
09375
09376
09377
09378 if (nlines)
09379 nlines[i] = usedLines;
09380 if (error)
09381 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
09382
09383 for (k = 0; k <= order; k++) {
09384 if (k > uorder) {
09385 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
09386 }
09387 else {
09388 cpl_table_set_double(idscoeff, clab[k], i,
09389 cpl_polynomial_get_coeff(ids, &k));
09390 }
09391 }
09392
09393 cpl_polynomial_delete(ids);
09394 cpl_bivector_delete(peaks_ident);
09395 }
09396 cpl_vector_delete(peaks);
09397 }
09398 }
09399
09400
09401 if (sradius > 0) {
09402
09403
09404
09405
09406
09407 nfits = row_top - row_bot - cpl_table_count_invalid(coeff, clab[0]);
09408
09409 if (nfits) {
09410 int slope = 0;
09411
09412 fguess = cpl_polynomial_new(1);
09413
09414 if (mos_interpolate_wavecalib_mos(coeff, 2, 1)) {
09415
09416 slope = 0;
09417
09418
09419
09420
09421
09422 for (k = 0; k <= order; k++) {
09423 c = cpl_table_get_column_median(coeff, clab[k]);
09424 cpl_polynomial_set_coeff(fguess, &k, c);
09425 }
09426 }
09427 else {
09428 slope = 1;
09429 }
09430
09431 for (i = row_bot; i < row_top; i++) {
09432 cpl_bivector * peaks_ident_used_fit;
09433
09434
09435
09436
09437
09438 width = mos_lines_width(sdata + i*nx, nx);
09439 if (width > sradius) {
09440 uradius = width;
09441 }
09442 else {
09443 uradius = sradius;
09444 }
09445
09446 if (slope) {
09447 for (k = 0; k <= order; k++) {
09448 c = cpl_table_get_double(coeff, clab[k],
09449 i - row_bot, NULL);
09450 cpl_polynomial_set_coeff(fguess, &k, c);
09451 }
09452 }
09453
09454 peaks_ident = mos_find_peaks(sdata + i*nx, nx, lines,
09455 fguess, refwave, uradius);
09456
09457 if (peaks_ident == NULL) {
09458 cpl_error_reset();
09459 continue;
09460 }
09461
09462 countLines = cpl_bivector_get_size(peaks_ident);
09463
09464 if (countLines < 4) {
09465 cpl_bivector_delete(peaks_ident);
09466 continue;
09467 }
09468
09469
09470
09471
09472
09473 wavel = cpl_bivector_get_y(peaks_ident);
09474 cpl_vector_subtract_scalar(wavel, refwave);
09475
09476 uorder = countLines / 2 - 1;
09477 if (uorder > order)
09478 uorder = order;
09479
09480 ids = mos_poly_wav2pix(peaks_ident, uorder, reject,
09481 2 * (uorder + 1), &usedLines,
09482 &ids_err, &peaks_ident_used_fit);
09483
09484 if (ids == NULL) {
09485 cpl_error_reset();
09486 cpl_bivector_delete(peaks_ident);
09487 continue;
09488 }
09489
09490 if (nlines)
09491 nlines[i] = usedLines;
09492 if (error)
09493 error[i] = ids_err / sqrt(usedLines/(uorder + 1));
09494
09495 if (calibration) {
09496 pixstart = cpl_polynomial_eval_1d(ids,
09497 cpl_bivector_get_y_data(peaks_ident)[0],
09498 NULL);
09499 pixend = cpl_polynomial_eval_1d(ids,
09500 cpl_bivector_get_y_data(peaks_ident)[countLines-1],
09501 NULL);
09502 extrapolation = (pixend - pixstart) / 5;
09503 pixstart -= extrapolation;
09504 pixend += extrapolation;
09505 if (pixstart < 0)
09506 pixstart = 0;
09507 if (pixend > nx)
09508 pixend = nx;
09509
09510 for (j = pixstart; j < pixend; j++) {
09511 (idata + i*nx)[j] = mos_eval_dds(ids,
09512 firstLambda, lastLambda, refwave, j);
09513 }
09514 }
09515
09516
09517
09518
09519
09520 if (residuals || (restable && !(i%step))) {
09521 if (restable && !(i%step)) {
09522 lin = cpl_polynomial_new(1);
09523 for (k = 0; k < 2; k++)
09524 cpl_polynomial_set_coeff(lin, &k,
09525 cpl_polynomial_get_coeff(ids, &k));
09526 }
09527 for (j = 0; j < countLines; j++) {
09528 pixe = cpl_bivector_get_x_data(peaks_ident)[j];
09529 wave = cpl_bivector_get_y_data(peaks_ident)[j];
09530 value = pixe
09531 - cpl_polynomial_eval_1d(ids, wave, NULL);
09532 if (residuals) {
09533 pixel = pixe + 0.5;
09534 (ddata + i*nx)[pixel] = value;
09535 }
09536 if (restable && !(i%step)) {
09537 for (k = 0; k < nref; k++) {
09538 if (fabs(line[k]-refwave-wave) < 0.1) {
09539 snprintf(name, MAX_COLNAME,
09540 "r%d", i);
09541 cpl_table_set_double(restable, name,
09542 k, value);
09543 value = pixe
09544 - cpl_polynomial_eval_1d(lin,
09545 wave, NULL);
09546 snprintf(name, MAX_COLNAME,
09547 "d%d", i);
09548 cpl_table_set_double(restable, name,
09549 k, value);
09550 snprintf(name, MAX_COLNAME,
09551 "p%d", i);
09552 cpl_table_set_double(restable, name,
09553 k, pixe);
09554 break;
09555 }
09556 }
09557 }
09558 }
09559 if (restable && !(i%step)) {
09560 cpl_polynomial_delete(lin);
09561 }
09562
09563
09564
09565
09566
09567
09568
09569
09570
09571
09572
09573 }
09574
09575 if(detected_lines)
09576 {
09577 cpl_size oldsize = cpl_table_get_nrow(detected_lines);
09578 cpl_size nidentlines = cpl_bivector_get_size(peaks_ident);
09579 cpl_table_set_size(detected_lines, oldsize + nidentlines);
09580 for(cpl_size idline = 0; idline < nidentlines ; ++idline)
09581 {
09582 double wave_ident = cpl_bivector_get_y_data(peaks_ident)[idline] + refwave;
09583 double xpix_fit = cpl_polynomial_eval_1d(ids,
09584 wave_ident - refwave, NULL);
09585 cpl_table_set_int(detected_lines, "slit_id",
09586 oldsize + idline, slit_id);
09587 cpl_table_set_double(detected_lines, "xpos_rectified_iter",
09588 oldsize + idline, cpl_bivector_get_x_data(peaks_ident)[idline] + 1);
09589 cpl_table_set_double(detected_lines, "ypos_rectified_iter",
09590 oldsize + idline, (double)i + 1);
09591 cpl_table_set_double(detected_lines, "peak_flux",
09592 oldsize + idline,
09593 sdata[i*nx+(int)(cpl_bivector_get_x_data(peaks_ident)[idline]+0.5)]);
09594 cpl_table_set_double(detected_lines, "wave_ident_iter",
09595 oldsize + idline, wave_ident);
09596 cpl_table_set_double(detected_lines, "xpos_fit_rect_wavecal",
09597 oldsize + idline, xpix_fit + 1);
09598 cpl_table_set_int(detected_lines,
09599 "fit_used",
09600 oldsize + idline, 0);
09601 for(cpl_size i_used = 0; i_used < cpl_bivector_get_size(peaks_ident_used_fit); ++i_used)
09602 {
09603 if(cpl_bivector_get_x_data(peaks_ident)[idline] == cpl_bivector_get_x_data(peaks_ident_used_fit)[i_used])
09604 cpl_table_set_int(detected_lines,
09605 "fit_used",
09606 oldsize + idline, 1);
09607 }
09608 }
09609 }
09610
09611
09612 for (k = 0; k <= order; k++) {
09613 if (k > uorder) {
09614 cpl_table_set_double(idscoeff, clab[k], i, 0.0);
09615 }
09616 else {
09617 cpl_table_set_double(idscoeff, clab[k], i,
09618 cpl_polynomial_get_coeff(ids, &k));
09619 }
09620 }
09621
09622 cpl_bivector_delete(peaks_ident);
09623 cpl_polynomial_delete(ids);
09624
09625 }
09626
09627 cpl_polynomial_delete(fguess);
09628 }
09629
09630 cpl_table_delete(coeff);
09631
09632 }
09633
09634 row_top = row_bot;
09635
09636 }
09637
09638
09639
09640
09641
09642
09643
09644
09645
09646 for (i = 0; i < ny; i++) {
09647
09648 missing = 0;
09649 ids = cpl_polynomial_new(1);
09650 for (k = 0; k <= order; k++) {
09651 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
09652 if (null) {
09653 cpl_polynomial_delete(ids);
09654 missing = 1;
09655 break;
09656 }
09657 cpl_polynomial_set_coeff(ids, &k, c);
09658 }
09659 if (missing)
09660 continue;
09661
09662 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
09663 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
09664 if (pixstart < 0)
09665 pixstart = 0;
09666 if (pixend > nx)
09667 pixend = nx;
09668
09669
09670
09671
09672
09673 for (j = 0; j < nl; j++) {
09674 lambda = firstLambda + j * dispersion;
09675 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave, NULL);
09676 pixel = fpixel;
09677 if (pixel >= 0 && pixel < nx-1) {
09678 v1 = (sdata + i*nx)[pixel];
09679 v2 = (sdata + i*nx)[pixel+1];
09680 vi = v1 + (v2-v1)*(fpixel-pixel);
09681 (rdata + i*nl)[j] = vi;
09682 }
09683 }
09684
09685 cpl_polynomial_delete(ids);
09686 }
09687
09688 return resampled;
09689 }
09690
09691
09718 cpl_image *mos_wavelength_calibration(cpl_image *image, double refwave,
09719 double firstLambda, double lastLambda,
09720 double dispersion, cpl_table *idscoeff,
09721 int flux)
09722 {
09723
09724 const char *func = "mos_wavelength_calibration";
09725
09726 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
09727
09728
09729 cpl_image *resampled;
09730 cpl_polynomial *ids;
09731 double pixel_per_lambda;
09732 double lambda;
09733 double c;
09734 float *sdata;
09735 float *rdata;
09736 float v0, v1, v2, v3, vi;
09737 float fpixel;
09738 int order;
09739 int pixstart, pixend;
09740 int nl, nx, ny, pixel;
09741 int missing;
09742 int null;
09743 int i, j;
09744 cpl_size k;
09745
09746
09747 if (dispersion <= 0.0) {
09748 cpl_msg_error(func, "The resampling step must be positive");
09749 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
09750 return NULL;
09751 }
09752
09753 if (lastLambda - firstLambda < dispersion) {
09754 cpl_msg_error(func, "Invalid spectral range: %.2f to %.2f",
09755 firstLambda, lastLambda);
09756 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
09757 return NULL;
09758 }
09759
09760 if (idscoeff == NULL) {
09761 cpl_msg_error(func, "An IDS coeff table must be given");
09762 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09763 return NULL;
09764 }
09765
09766 if (image == NULL) {
09767 cpl_msg_error(func, "A scientific spectral image must be given");
09768 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
09769 return NULL;
09770 }
09771
09772 nx = cpl_image_get_size_x(image);
09773 ny = cpl_image_get_size_y(image);
09774 sdata = cpl_image_get_data_float(image);
09775
09776 nl = (lastLambda - firstLambda) / dispersion;
09777 resampled = cpl_image_new(nl, ny, CPL_TYPE_FLOAT);
09778 rdata = cpl_image_get_data_float(resampled);
09779
09780 order = 0;
09781 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
09782 ++order;
09783 --order;
09784
09785 for (i = 0; i < ny; i++) {
09786
09787 missing = 0;
09788 ids = cpl_polynomial_new(1);
09789 for (k = 0; k <= order; k++) {
09790 c = cpl_table_get_double(idscoeff, clab[k], i, &null);
09791 if (null) {
09792 cpl_polynomial_delete(ids);
09793 missing = 1;
09794 break;
09795 }
09796 cpl_polynomial_set_coeff(ids, &k, c);
09797 }
09798 if (missing)
09799 continue;
09800
09801 pixstart = cpl_polynomial_eval_1d(ids, firstLambda - refwave, NULL);
09802 pixend = cpl_polynomial_eval_1d(ids, lastLambda - refwave, NULL);
09803 if (pixstart < 0)
09804 pixstart = 0;
09805 if (pixend > nx)
09806 pixend = nx;
09807
09808
09809
09810
09811
09812 for (j = 0; j < nl; j++) {
09813 lambda = firstLambda + j * dispersion;
09814 fpixel = cpl_polynomial_eval_1d(ids, lambda - refwave,
09815 &pixel_per_lambda);
09816
09817
09818
09819
09820
09821
09822
09823 pixel = fpixel;
09824
09825
09826 if (1) {
09827
09828
09829
09830
09831
09832
09833
09834
09835
09836 if(pixel_per_lambda <= 0)
09837 vi = 0;
09838 else if (fpixel < 0)
09839 vi = 0;
09840 else if (pixel >= 1 && pixel < nx-2) {
09841 v0 = (sdata + i*nx)[pixel-1];
09842 v1 = (sdata + i*nx)[pixel];
09843 v2 = (sdata + i*nx)[pixel+1];
09844 v3 = (sdata + i*nx)[pixel+2];
09845 vi = (fpixel-pixel)*(fpixel-pixel)*(v3 - v2 - v1 + v0)
09846 + (fpixel-pixel)*(3*v2 - v3 - v1 - v0)
09847 + 2*v1;
09848 vi /= 2;
09849 if (v1 > v2) {
09850 if (vi > v1) {
09851 vi = v1;
09852 }
09853 else if (vi < v2) {
09854 vi = v2;
09855 }
09856 }
09857 else {
09858 if (vi > v2) {
09859 vi = v2;
09860 }
09861 else if (vi < v1) {
09862 vi = v1;
09863 }
09864 }
09865 if (flux)
09866 vi *= dispersion * pixel_per_lambda;
09867 }
09868 else if (pixel >= 0 && pixel < nx-1) {
09869 v1 = (sdata + i*nx)[pixel];
09870 v2 = (sdata + i*nx)[pixel+1];
09871 vi = v1 + (v2-v1)*(fpixel-pixel);
09872 if (flux)
09873 vi *= dispersion * pixel_per_lambda;
09874 }
09875 else
09876 vi = 0;
09877 (rdata + i*nl)[j] = vi;
09878 }
09879 else {
09880
09881
09882
09883
09884
09885
09886
09887
09888
09889
09890 double spos = fpixel - dispersion * pixel_per_lambda / 2;
09891 double epos = fpixel + dispersion * pixel_per_lambda / 2;
09892
09893
09894
09895
09896
09897 int spix = spos;
09898 int epix = epos + 1;
09899
09900 if (spix < 0)
09901 spix = 0;
09902
09903 if (epix > nx)
09904 epix = nx;
09905
09906 vi = 0.0;
09907 for (k = spix; k < epix; k++) {
09908 if (pixel >= 0 && pixel < nx) {
09909 vi += (sdata + i*nx)[k];
09910 }
09911 }
09912
09913
09914
09915
09916
09917
09918
09919
09920 vi *= dispersion * pixel_per_lambda / (epix - spix);
09921
09922
09923
09924
09925
09926
09927 if (flux)
09928 vi *= dispersion * pixel_per_lambda;
09929
09930 (rdata + i*nl)[j] = vi;
09931 }
09932 }
09933
09934 cpl_polynomial_delete(ids);
09935 }
09936
09937 return resampled;
09938 }
09939
09940
10007 cpl_table *mos_wavelength_align(cpl_image *image, cpl_table *slits,
10008 double refwave, double firstLambda,
10009 double lastLambda, cpl_table *idscoeff,
10010 cpl_vector *skylines, int highres, int order,
10011 cpl_image *calibration, int sradius)
10012 {
10013 const char *func = "mos_wavelength_align";
10014
10015 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10016
10017 double *line;
10018 double *data;
10019 double expPos, offset;
10020 double c;
10021 double lambda1, lambda2;
10022 double rms;
10023 float pos;
10024 float *sdata;
10025 float *cdata;
10026 int *idata;
10027 int startPos, endPos;
10028 int window = 2*sradius + 1;
10029 int nlines;
10030 int nslits;
10031 int npoints;
10032 int nrows;
10033 int nx, ny;
10034 int xlow, ylow, xhig, yhig;
10035 int idsorder, uorder;
10036 int *slit_id;
10037 int *position;
10038 int *length;
10039 int missing;
10040 int null;
10041 int i;
10042 cpl_size j, k;
10043
10044 char offname[MAX_COLNAME];
10045 char name[MAX_COLNAME];
10046
10047 cpl_polynomial *ids;
10048 cpl_polynomial *polycorr;
10049 cpl_image *exslit;
10050 cpl_image *sky;
10051 cpl_table *offsets;
10052 cpl_table *dummy;
10053 cpl_vector *wave;
10054 cpl_vector *offs;
10055
10056
10057 if (idscoeff == NULL) {
10058 cpl_msg_error(func, "An IDS coeff table must be given");
10059 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10060 return NULL;
10061 }
10062
10063 if (image == NULL) {
10064 cpl_msg_error(func, "A scientific spectral image must be given");
10065 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10066 return NULL;
10067 }
10068
10069 if (slits == NULL) {
10070 cpl_msg_error(func, "A slit position table must be given");
10071 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10072 return NULL;
10073 }
10074
10075 if (skylines) {
10076 line = cpl_vector_get_data(skylines);
10077 nlines = cpl_vector_get_size(skylines);
10078 }
10079 else {
10080 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
10081 "given: using internal list of reference sky lines");
10082 if (highres) {
10083 line = default_lines_hi;
10084 nlines = sizeof(default_lines_hi) / sizeof(double);
10085 }
10086 else {
10087 line = default_lines_lo;
10088 nlines = sizeof(default_lines_lo) / sizeof(double);
10089 }
10090 }
10091
10092 if (calibration)
10093 cdata = cpl_image_get_data(calibration);
10094
10095 nx = cpl_image_get_size_x(image);
10096 ny = cpl_image_get_size_y(image);
10097
10098 nslits = cpl_table_get_nrow(slits);
10099 slit_id = cpl_table_get_data_int(slits, "slit_id");
10100 position = cpl_table_get_data_int(slits, "position");
10101 length = cpl_table_get_data_int(slits, "length");
10102
10103
10104
10105
10106
10107
10108 nrows = 0;
10109 for (i = 0; i < nlines; i++)
10110 if (line[i] > firstLambda && line[i] < lastLambda)
10111 nrows++;
10112
10113 offsets = cpl_table_new(nrows);
10114 cpl_table_new_column(offsets, "wave", CPL_TYPE_DOUBLE);
10115 cpl_table_set_column_unit(offsets, "wave", "Angstrom");
10116
10117 nrows = 0;
10118 for (i = 0; i < nlines; i++) {
10119 if (line[i] > firstLambda && line[i] < lastLambda) {
10120 cpl_table_set_double(offsets, "wave", nrows, line[i]);
10121 nrows++;
10122 }
10123 }
10124
10125
10126
10127
10128
10129 line = cpl_table_get_data_double(offsets, "wave");
10130 nlines = nrows;
10131
10132 idsorder = 0;
10133 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
10134 ++idsorder;
10135 --idsorder;
10136
10137 xlow = 1;
10138 xhig = nx;
10139 for (i = 0; i < nslits; i++) {
10140
10141 if (length[i] == 0)
10142 continue;
10143
10144 snprintf(offname, MAX_COLNAME, "offset%d", slit_id[i]);
10145 cpl_table_new_column(offsets, offname, CPL_TYPE_DOUBLE);
10146
10147
10148
10149
10150
10151
10152
10153
10154
10155
10156
10157 ylow = position[i] + 1;
10158 yhig = ylow + length[i] - 1;
10159
10160 exslit = cpl_image_extract(image, xlow, ylow, xhig, yhig);
10161 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
10162 sdata = cpl_image_get_data(sky);
10163
10164 cpl_image_delete(exslit);
10165
10166
10167
10168
10169
10170
10171 ylow--;
10172
10173
10174
10175
10176
10177
10178
10179 dummy = cpl_table_new(yhig - ylow);
10180 for (j = 0; j < nlines; j++) {
10181 snprintf(name, MAX_COLNAME, "%"CPL_SIZE_FORMAT, j);
10182 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
10183 }
10184
10185 for (j = ylow; j < yhig; j++) {
10186
10187
10188
10189
10190
10191 missing = 0;
10192 ids = cpl_polynomial_new(1);
10193 for (k = 0; k <= idsorder; k++) {
10194 c = cpl_table_get_double(idscoeff, clab[k], j, &null);
10195 if (null) {
10196 cpl_polynomial_delete(ids);
10197 missing = 1;
10198 break;
10199 }
10200 cpl_polynomial_set_coeff(ids, &k, c);
10201 }
10202 if (missing)
10203 continue;
10204
10205 for (k = 0; k < nlines; k++) {
10206 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
10207 startPos = expPos - sradius;
10208 endPos = startPos + window;
10209 if (startPos < 0 || endPos >= nx)
10210 continue;
10211
10212 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
10213 pos += startPos;
10214 offset = pos - expPos;
10215 snprintf(name, MAX_COLNAME, "%"CPL_SIZE_FORMAT, k);
10216 cpl_table_set_double(dummy, name, j - ylow, offset);
10217 }
10218 }
10219
10220 cpl_polynomial_delete(ids);
10221 }
10222
10223 cpl_image_delete(sky);
10224
10225 for (j = 0; j < nlines; j++) {
10226 snprintf(name, MAX_COLNAME, "%"CPL_SIZE_FORMAT, j);
10227 if (cpl_table_has_valid(dummy, name)) {
10228 offset = cpl_table_get_column_median(dummy, name);
10229 cpl_table_set_double(offsets, offname, j, offset);
10230 }
10231 }
10232
10233 cpl_table_delete(dummy);
10234
10235 }
10236
10237
10238
10239
10240
10241
10242
10243
10244 for (i = 0; i < nslits; i++) {
10245
10246 if (length[i] == 0)
10247 continue;
10248
10249 snprintf(offname, MAX_COLNAME, "offset%d", slit_id[i]);
10250
10251
10252
10253
10254
10255
10256 dummy = cpl_table_new(nlines);
10257 cpl_table_duplicate_column(dummy, "wave", offsets, "wave");
10258 cpl_table_duplicate_column(dummy, "offset", offsets, offname);
10259
10260 npoints = nlines - cpl_table_count_invalid(dummy, "offset");
10261 if (npoints == 0) {
10262 cpl_msg_warning(func, "No sky lines alignment was possible "
10263 "for slit ID=%d: no sky line found", slit_id[i]);
10264 cpl_table_delete(dummy);
10265 continue;
10266 }
10267
10268 uorder = order;
10269 if (npoints <= uorder) {
10270 uorder = npoints - 1;
10271 if (uorder) {
10272 cpl_msg_warning(func, "Just %d sky lines detected for slit "
10273 "ID=%d, while a polynomial order %d was "
10274 "requested. Using polynomial order %d for "
10275 "this slit!", npoints, slit_id[i], order,
10276 uorder);
10277 }
10278 else {
10279 cpl_msg_warning(func, "Just %d sky lines detected for slit "
10280 "ID=%d, while a polynomial order %d was "
10281 "requested. Computing a median offset for "
10282 "this slit!", npoints, slit_id[i], order);
10283 }
10284 }
10285
10286 cpl_table_erase_invalid(dummy);
10287
10288 if (uorder > 1) {
10289
10290
10291
10292
10293
10294 wave = cpl_vector_wrap(npoints,
10295 cpl_table_get_data_double(dummy, "wave"));
10296 offs = cpl_vector_wrap(npoints,
10297 cpl_table_get_data_double(dummy, "offset"));
10298
10299
10300
10301
10302
10303 cpl_vector_subtract_scalar(wave, refwave);
10304
10305 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
10306
10307 rms = sqrt(rms * (uorder + 1) / npoints);
10308
10309 cpl_vector_unwrap(wave);
10310 cpl_vector_unwrap(offs);
10311 cpl_table_delete(dummy);
10312
10313
10314
10315
10316
10317
10318 ylow = position[i];
10319 yhig = ylow + length[i];
10320
10321 for (j = 0; j <= uorder; j++) {
10322 data = cpl_table_get_data_double(idscoeff, clab[j]);
10323 c = cpl_polynomial_get_coeff(polycorr, &j);
10324 for (k = ylow; k < yhig; k++)
10325 data[k] += c;
10326 }
10327
10328 data = cpl_table_get_data_double(idscoeff, "error");
10329 for (k = ylow; k < yhig; k++)
10330 data[k] = sqrt(data[k]*data[k] + rms*rms);
10331
10332 idata = cpl_table_get_data_int(idscoeff, "nlines");
10333 for (k = ylow; k < yhig; k++)
10334 idata[k] = npoints;
10335
10336
10337
10338
10339
10340
10341 if (calibration) {
10342 for (j = ylow; j < yhig; j++) {
10343 for (k = 1; k < nx; k++) {
10344 lambda1 = cdata[k - 1 + j*nx];
10345 lambda2 = cdata[k + j*nx];
10346 if (lambda1 < 1.0 || lambda2 < 1.0)
10347 continue;
10348 offset = cpl_polynomial_eval_1d(polycorr,
10349 lambda1-refwave, NULL);
10350 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
10351 }
10352 }
10353 }
10354
10355 cpl_polynomial_delete(polycorr);
10356 }
10357 else if (uorder == 1) {
10358
10359
10360
10361
10362
10363 double q, m;
10364 cpl_bivector *list;
10365
10366
10367 wave = cpl_vector_wrap(npoints,
10368 cpl_table_get_data_double(dummy, "wave"));
10369 offs = cpl_vector_wrap(npoints,
10370 cpl_table_get_data_double(dummy, "offset"));
10371
10372 list = cpl_bivector_wrap_vectors(wave, offs);
10373
10374
10375
10376
10377
10378 cpl_vector_subtract_scalar(wave, refwave);
10379
10380 robustLinearFit(list, &q, &m, &rms);
10381
10382 rms = sqrt(rms * (uorder + 1) / npoints);
10383
10384 cpl_bivector_unwrap_vectors(list);
10385 cpl_vector_unwrap(wave);
10386 cpl_vector_unwrap(offs);
10387 cpl_table_delete(dummy);
10388
10389
10390
10391
10392
10393
10394 ylow = position[i];
10395 yhig = ylow + length[i];
10396
10397 for (j = 0; j <= uorder; j++) {
10398 data = cpl_table_get_data_double(idscoeff, clab[j]);
10399 if (j)
10400 c = m;
10401 else
10402 c = q;
10403 for (k = ylow; k < yhig; k++)
10404 data[k] += c;
10405 }
10406
10407 data = cpl_table_get_data_double(idscoeff, "error");
10408 for (k = ylow; k < yhig; k++)
10409 data[k] = sqrt(data[k]*data[k] + rms*rms);
10410
10411 idata = cpl_table_get_data_int(idscoeff, "nlines");
10412 for (k = ylow; k < yhig; k++)
10413 idata[k] = npoints;
10414
10415
10416
10417
10418
10419
10420 if (calibration) {
10421 for (j = ylow; j < yhig; j++) {
10422 for (k = 1; k < nx; k++) {
10423 lambda1 = cdata[k - 1 + j*nx];
10424 lambda2 = cdata[k + j*nx];
10425 if (lambda1 < 1.0 || lambda2 < 1.0)
10426 continue;
10427 offset = q + m*(lambda1-refwave);
10428 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
10429 }
10430 }
10431 }
10432 }
10433 else {
10434
10435
10436
10437
10438
10439 offs = cpl_vector_wrap(npoints,
10440 cpl_table_get_data_double(dummy, "offset"));
10441
10442 offset = cpl_vector_get_median_const(offs);
10443
10444 if (npoints > 1)
10445 rms = cpl_table_get_column_stdev(dummy, "offset");
10446 else
10447 rms = 0.0;
10448
10449 rms /= sqrt(npoints);
10450
10451 cpl_vector_unwrap(offs);
10452 cpl_table_delete(dummy);
10453
10454
10455
10456
10457
10458
10459 ylow = position[i];
10460 yhig = ylow + length[i];
10461
10462 data = cpl_table_get_data_double(idscoeff, clab[0]);
10463 for (k = ylow; k < yhig; k++)
10464 data[k] += offset;
10465
10466 data = cpl_table_get_data_double(idscoeff, "error");
10467 for (k = ylow; k < yhig; k++)
10468 data[k] = sqrt(data[k]*data[k] + rms*rms);
10469
10470 idata = cpl_table_get_data_int(idscoeff, "nlines");
10471 for (k = ylow; k < yhig; k++)
10472 idata[k] = npoints;
10473
10474
10475
10476
10477
10478
10479
10480 if (calibration) {
10481 for (j = ylow; j < yhig; j++) {
10482 for (k = 1; k < nx; k++) {
10483 lambda1 = cdata[k - 1 + j*nx];
10484 lambda2 = cdata[k + j*nx];
10485 if (lambda1 < 1.0 || lambda2 < 1.0)
10486 continue;
10487 cdata[k - 1 + j*nx] -= offset * (lambda2-lambda1);
10488 }
10489 }
10490 }
10491 }
10492 }
10493
10494 return offsets;
10495
10496 }
10497
10498
10560 cpl_table *mos_wavelength_align_lss(cpl_image *image, double refwave,
10561 double firstLambda, double lastLambda,
10562 cpl_table *idscoeff, cpl_vector *skylines,
10563 int highres, int order,
10564 cpl_image *calibration, int sradius)
10565 {
10566 const char *func = "mos_wavelength_align_lss";
10567
10568 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
10569
10570 double *line;
10571 double *data;
10572 double *wdata;
10573 double *odata;
10574 double expPos, offset;
10575 double c;
10576 double lambda1, lambda2;
10577 double rms;
10578 float pos;
10579 float *sdata;
10580 float *cdata;
10581 int *idata;
10582 int startPos, endPos;
10583 int window = 2*sradius + 1;
10584 int nlines;
10585 int npoints;
10586 int nrows;
10587 int nx, ny;
10588 int idsorder, uorder;
10589 int missing;
10590 int i;
10591 cpl_size j, k;
10592
10593 char name[MAX_COLNAME];
10594 char fname[MAX_COLNAME];
10595
10596 cpl_polynomial *ids;
10597 cpl_polynomial *polycorr;
10598 cpl_table *offsets;
10599 cpl_table *fittable;
10600 cpl_table *dummy;
10601 cpl_vector *wave;
10602 cpl_vector *offs;
10603 cpl_vector *row;
10604
10605
10606 if (idscoeff == NULL) {
10607 cpl_msg_error(func, "An IDS coeff table must be given");
10608 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10609 return NULL;
10610 }
10611
10612 if (image == NULL) {
10613 cpl_msg_error(func, "A scientific spectral image must be given");
10614 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
10615 return NULL;
10616 }
10617
10618 if (skylines) {
10619 line = cpl_vector_get_data(skylines);
10620 nlines = cpl_vector_get_size(skylines);
10621 }
10622 else {
10623 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
10624 "given: using internal list of reference sky lines");
10625 if (highres) {
10626 line = default_lines_hi;
10627 nlines = sizeof(default_lines_hi) / sizeof(double);
10628 }
10629 else {
10630 line = default_lines_lo;
10631 nlines = sizeof(default_lines_lo) / sizeof(double);
10632 }
10633 }
10634
10635 if (calibration)
10636 cdata = cpl_image_get_data(calibration);
10637
10638 nx = cpl_image_get_size_x(image);
10639 ny = cpl_image_get_size_y(image);
10640
10641 sdata = cpl_image_get_data(image);
10642
10643 if (ny != cpl_table_get_nrow(idscoeff)) {
10644 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
10645 return NULL;
10646 }
10647
10648
10649
10650
10651
10652
10653
10654
10655
10656
10657 nrows = 0;
10658 for (i = 0; i < nlines; i++)
10659 if (line[i] > firstLambda && line[i] < lastLambda)
10660 nrows++;
10661
10662 offsets = cpl_table_new(nrows);
10663 cpl_table_new_column(offsets, "wave", CPL_TYPE_DOUBLE);
10664 cpl_table_set_column_unit(offsets, "wave", "Angstrom");
10665
10666 nrows = 0;
10667 for (i = 0; i < nlines; i++) {
10668 if (line[i] > firstLambda && line[i] < lastLambda) {
10669 cpl_table_set_double(offsets, "wave", nrows, line[i]);
10670 nrows++;
10671 }
10672 }
10673
10674
10675
10676
10677
10678 line = cpl_table_get_data_double(offsets, "wave");
10679 nlines = nrows;
10680
10681 idsorder = 0;
10682 while (idsorder < 6 && cpl_table_has_column(idscoeff, clab[idsorder]))
10683 ++idsorder;
10684 --idsorder;
10685
10686
10687
10688
10689
10690
10691
10692 dummy = cpl_table_new(ny);
10693 for (j = 0; j < nlines; j++) {
10694 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
10695 snprintf(fname, MAX_COLNAME, "fit_%d", (int)line[j]);
10696 cpl_table_new_column(dummy, name, CPL_TYPE_DOUBLE);
10697 cpl_table_new_column(dummy, fname, CPL_TYPE_DOUBLE);
10698 }
10699
10700 for (j = 0; j < ny; j++, sdata += nx) {
10701
10702
10703
10704
10705
10706 missing = 0;
10707 ids = cpl_polynomial_new(1);
10708 for (k = 0; k <= idsorder; k++) {
10709 c = cpl_table_get_double(idscoeff, clab[k], j, &missing);
10710 if (missing) {
10711 cpl_polynomial_delete(ids);
10712 break;
10713 }
10714 cpl_polynomial_set_coeff(ids, &k, c);
10715 }
10716 if (missing)
10717 continue;
10718
10719 for (k = 0; k < nlines; k++) {
10720 expPos = cpl_polynomial_eval_1d(ids, line[k] - refwave, NULL);
10721 startPos = expPos - sradius;
10722 endPos = startPos + window;
10723 if (startPos < 0 || endPos >= nx)
10724 continue;
10725
10726 if (0 == peakPosition(sdata + startPos, window, &pos, 1)) {
10727 pos += startPos;
10728 offset = pos - expPos;
10729 snprintf(name, MAX_COLNAME, "off_%d", (int)line[k]);
10730 cpl_table_set_double(dummy, name, j, offset);
10731 }
10732 }
10733
10734 cpl_polynomial_delete(ids);
10735 }
10736
10737
10738
10739
10740
10741
10742
10743 for (j = 0; j < nlines; j++) {
10744 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
10745 snprintf(fname, MAX_COLNAME, "fit_%d", (int)line[j]);
10746 if (cpl_table_has_valid(dummy, name)) {
10747
10748
10749
10750
10751
10752
10753 double q, m;
10754 cpl_bivector *list;
10755
10756 fittable = cpl_table_new(ny);
10757 cpl_table_new_column(fittable, "row", CPL_TYPE_DOUBLE);
10758 cpl_table_set_column_unit(fittable, "row", "pixel");
10759 for (k = 0; k < ny; k++)
10760 cpl_table_set_double(fittable, "row", k, k);
10761 cpl_table_duplicate_column(fittable, "offset", dummy, name);
10762 npoints = ny - cpl_table_count_invalid(fittable, "offset");
10763 cpl_table_erase_invalid(fittable);
10764 row = cpl_vector_wrap(npoints,
10765 cpl_table_get_data_double(fittable, "row"));
10766 offs = cpl_vector_wrap(npoints,
10767 cpl_table_get_data_double(fittable, "offset"));
10768 list = cpl_bivector_wrap_vectors(row, offs);
10769 robustLinearFit(list, &q, &m, &rms);
10770 cpl_bivector_unwrap_vectors(list);
10771 cpl_vector_unwrap(row);
10772 cpl_vector_unwrap(offs);
10773 cpl_table_delete(fittable);
10774 for (k = 0; k < ny; k++)
10775 cpl_table_set_double(dummy, fname, k, q + m*k);
10776 }
10777 }
10778
10779
10780
10781
10782
10783
10784
10785
10786
10787
10788 for (i = 0; i < ny; i++) {
10789
10790 if (!cpl_table_is_valid(idscoeff, clab[0], i))
10791 continue;
10792
10793 npoints = 0;
10794 for (j = 0; j < nlines; j++) {
10795 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
10796 if (cpl_table_is_valid(dummy, name, i))
10797 npoints++;
10798 }
10799
10800 if (npoints == 0)
10801 continue;
10802
10803 uorder = order;
10804 if (npoints <= uorder)
10805 uorder = npoints - 1;
10806
10807 if (uorder > 1) {
10808
10809
10810
10811
10812
10813 wave = cpl_vector_new(npoints);
10814 wdata = cpl_vector_get_data(wave);
10815 offs = cpl_vector_new(npoints);
10816 odata = cpl_vector_get_data(offs);
10817
10818 npoints = 0;
10819 for (j = 0; j < nlines; j++) {
10820 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
10821 if (cpl_table_is_valid(dummy, name, i)) {
10822 wdata[npoints] = line[j] - refwave;
10823 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10824 npoints++;
10825 }
10826 }
10827
10828 polycorr = cpl_polynomial_fit_1d_create(wave, offs, uorder, &rms);
10829
10830 rms = sqrt(rms * (uorder + 1) / npoints);
10831
10832 cpl_vector_delete(wave);
10833 cpl_vector_delete(offs);
10834
10835
10836
10837
10838
10839
10840 for (j = 0; j <= uorder; j++) {
10841 data = cpl_table_get_data_double(idscoeff, clab[j]);
10842 c = cpl_polynomial_get_coeff(polycorr, &j);
10843 data[i] += c;
10844 }
10845
10846 data = cpl_table_get_data_double(idscoeff, "error");
10847 data[i] = sqrt(data[i]*data[i] + rms*rms);
10848
10849 idata = cpl_table_get_data_int(idscoeff, "nlines");
10850 idata[i] = npoints;
10851
10852
10853
10854
10855
10856
10857 if (calibration) {
10858 for (k = 1; k < nx; k++) {
10859 lambda1 = cdata[k - 1 + i*nx];
10860 lambda2 = cdata[k + i*nx];
10861 if (lambda1 < 1.0 || lambda2 < 1.0)
10862 continue;
10863 offset = cpl_polynomial_eval_1d(polycorr,
10864 lambda1-refwave, NULL);
10865 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10866 }
10867 }
10868
10869 cpl_polynomial_delete(polycorr);
10870
10871 }
10872 else if (uorder == 1) {
10873
10874
10875
10876
10877
10878 cpl_bivector *list;
10879 double q, m;
10880
10881 wave = cpl_vector_new(npoints);
10882 wdata = cpl_vector_get_data(wave);
10883 offs = cpl_vector_new(npoints);
10884 odata = cpl_vector_get_data(offs);
10885
10886 npoints = 0;
10887 for (j = 0; j < nlines; j++) {
10888 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
10889 if (cpl_table_is_valid(dummy, name, i)) {
10890 wdata[npoints] = line[j] - refwave;
10891 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10892 npoints++;
10893 }
10894 }
10895
10896 list = cpl_bivector_wrap_vectors(wave, offs);
10897 robustLinearFit(list, &q, &m, &rms);
10898
10899 rms = sqrt(rms * (uorder + 1) / npoints);
10900
10901 cpl_bivector_unwrap_vectors(list);
10902 cpl_vector_delete(wave);
10903 cpl_vector_delete(offs);
10904
10905
10906
10907
10908
10909
10910 for (j = 0; j <= uorder; j++) {
10911 data = cpl_table_get_data_double(idscoeff, clab[j]);
10912 if (j)
10913 c = m;
10914 else
10915 c = q;
10916 data[i] += c;
10917 }
10918
10919 data = cpl_table_get_data_double(idscoeff, "error");
10920 data[i] = sqrt(data[i]*data[i] + rms*rms);
10921
10922 idata = cpl_table_get_data_int(idscoeff, "nlines");
10923 idata[i] = npoints;
10924
10925
10926
10927
10928
10929
10930 if (calibration) {
10931 for (k = 1; k < nx; k++) {
10932 lambda1 = cdata[k - 1 + i*nx];
10933 lambda2 = cdata[k + i*nx];
10934 if (lambda1 < 1.0 || lambda2 < 1.0)
10935 continue;
10936 offset = q + m*(lambda1-refwave);
10937 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
10938 }
10939 }
10940 }
10941 else {
10942
10943
10944
10945
10946
10947 offs = cpl_vector_new(npoints);
10948 odata = cpl_vector_get_data(offs);
10949
10950 npoints = 0;
10951 for (j = 0; j < nlines; j++) {
10952 snprintf(name, MAX_COLNAME, "fit_%d", (int)line[j]);
10953 if (cpl_table_is_valid(dummy, name, i)) {
10954 odata[npoints] = cpl_table_get_double(dummy, name, i, NULL);
10955 npoints++;
10956 }
10957 }
10958
10959 offset = cpl_vector_get_median_const(offs);
10960
10961 if (npoints > 1) {
10962 rms = cpl_vector_get_stdev(offs);
10963 }
10964 else if (npoints == 1) {
10965 snprintf(name, MAX_COLNAME, "off_%d", (int)line[0]);
10966 if (cpl_table_has_valid(dummy, name)) {
10967 rms = cpl_table_get_column_stdev(dummy, name);
10968 rms /= sqrt(ny - cpl_table_count_invalid(dummy, name));
10969 }
10970 else {
10971 rms = 0.0;
10972 }
10973 }
10974 else {
10975 rms = 0.0;
10976 }
10977
10978 rms /= sqrt(npoints);
10979
10980 cpl_vector_delete(offs);
10981
10982
10983
10984
10985
10986
10987 data = cpl_table_get_data_double(idscoeff, clab[0]);
10988 data[i] += offset;
10989
10990 data = cpl_table_get_data_double(idscoeff, "error");
10991 data[i] = sqrt(data[i]*data[i] + rms*rms);
10992
10993 idata = cpl_table_get_data_int(idscoeff, "nlines");
10994 idata[i] = npoints;
10995
10996
10997
10998
10999
11000
11001
11002 if (calibration) {
11003 for (k = 1; k < nx; k++) {
11004 lambda1 = cdata[k - 1 + i*nx];
11005 lambda2 = cdata[k + i*nx];
11006 if (lambda1 < 1.0 || lambda2 < 1.0)
11007 continue;
11008 cdata[k - 1 + i*nx] -= offset * (lambda2-lambda1);
11009 }
11010 }
11011 }
11012 }
11013
11014 missing = 1;
11015 for (j = 0; j < nlines; j++) {
11016 snprintf(name, MAX_COLNAME, "off_%d", (int)line[j]);
11017 if (cpl_table_has_valid(dummy, name)) {
11018 missing = 0;
11019 offset = cpl_table_get_column_median(dummy, name);
11020 cpl_msg_info(func, "Median offset for %.3f: %.3f pixel",
11021 line[j], offset);
11022 }
11023 else {
11024 cpl_msg_info(func,
11025 "Median offset for %.2f: not available", line[j]);
11026 }
11027 }
11028
11029 cpl_table_delete(offsets);
11030
11031 if (missing) {
11032 cpl_table_delete(dummy);
11033 dummy = NULL;
11034 }
11035
11036 return dummy;
11037
11038 }
11039
11040
11068 double mos_distortions_rms(cpl_image *rectified, cpl_vector *lines,
11069 double wavestart, double dispersion, int radius,
11070 int highres)
11071 {
11072
11073 const char *func = "mos_distortions_rms";
11074
11075 int xlen;
11076 int ylen;
11077 int numLines;
11078 int cpix, npix, nzero;
11079 int sp, ep;
11080 int i, j, k;
11081 int npeaks, allPeaks;
11082
11083 float *profile;
11084 float peak, expectPeak, offset;
11085 double lambda;
11086
11087 double average;
11088 double rms, oneRms;
11089
11090 float *sdata;
11091 double *wdata;
11092
11093
11094 xlen = cpl_image_get_size_x(rectified);
11095 ylen = cpl_image_get_size_y(rectified);
11096 sdata = cpl_image_get_data(rectified);
11097
11098 if (lines) {
11099 wdata = cpl_vector_get_data(lines);
11100 numLines = cpl_vector_get_size(lines);
11101 }
11102 else {
11103 cpl_msg_warning(func, "A catalog of sky lines wavelengths was not "
11104 "given: using internal list of reference sky lines");
11105 if (highres) {
11106 wdata = default_lines_hi;
11107 numLines = sizeof(default_lines_hi) / sizeof(double);
11108 }
11109 else {
11110 wdata = default_lines_lo;
11111 numLines = sizeof(default_lines_lo) / sizeof(double);
11112 }
11113 }
11114
11115 npix = 2 * radius + 1;
11116 profile = cpl_calloc(npix, sizeof(float));
11117
11118 rms = 0.0;
11119 allPeaks = 0;
11120
11121 for (i = 0; i < numLines; i++) {
11122
11123
11124
11125
11126
11127 lambda = wdata[i];
11128 expectPeak = (lambda - wavestart) / dispersion;
11129 cpix = floor(expectPeak + 0.5);
11130
11131
11132
11133
11134
11135 sp = cpix - radius;
11136 ep = cpix + radius;
11137
11138 if (sp < 0 || ep > xlen)
11139 continue;
11140
11141 average = 0.0;
11142 npeaks = 0;
11143 oneRms = 0.0;
11144
11145 for (j = 0; j < ylen; j++) {
11146 nzero = 0;
11147 for (k = 0; k < npix; k++) {
11148 profile[k] = sdata[sp + k + j * xlen];
11149 if (fabs(profile[k]) < 0.0001)
11150 nzero++;
11151 }
11152 if (nzero > 0)
11153 continue;
11154
11155 if (peakPosition(profile, npix, &peak, 1) == 0) {
11156 offset = (sp + peak) - expectPeak;
11157 average += offset;
11158 rms += fabs(offset);
11159 oneRms += fabs(offset);
11160 npeaks++;
11161 allPeaks++;
11162 }
11163 }
11164
11165 if (npeaks)
11166 cpl_msg_info(func, "RMS for %.2f: %.3f pixel (%d points)",
11167 lambda, oneRms / npeaks * 1.25, npeaks);
11168 else
11169 cpl_msg_info(func, "RMS for %.2f: line not available", lambda);
11170 }
11171
11172 cpl_free(profile);
11173
11174 if (allPeaks < 10)
11175 return 0.0;
11176
11177 rms /= allPeaks;
11178 rms *= 1.25;
11179
11180 return rms;
11181
11182 }
11183
11184
11205 cpl_image *mos_map_pixel(cpl_table *idscoeff, double reference,
11206 double blue, double red, double dispersion, int trend)
11207 {
11208 const char *func = "mos_map_pixel";
11209
11210 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
11211
11212
11213 cpl_polynomial *ids;
11214 cpl_image *map;
11215 float *mdata;
11216 double lambda;
11217 double c;
11218 int order;
11219 int xsize, ysize;
11220 int missing;
11221 int i, j;
11222 cpl_size k;
11223
11224
11225 if (idscoeff == NULL) {
11226 cpl_msg_error(func, "An IDS coeff table must be given");
11227 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11228 return NULL;
11229 }
11230
11231 xsize = (red - blue) / dispersion;
11232 ysize = cpl_table_get_nrow(idscoeff);
11233 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
11234 mdata = cpl_image_get_data(map);
11235
11236 order = 0;
11237 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
11238 ++order;
11239 --order;
11240
11241 for (i = 0; i < ysize; i++, mdata += xsize) {
11242
11243 missing = 0;
11244 ids = cpl_polynomial_new(1);
11245 for (k = trend; k <= order; k++) {
11246 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
11247 if (missing) {
11248 cpl_polynomial_delete(ids);
11249 break;
11250 }
11251 cpl_polynomial_set_coeff(ids, &k, c);
11252 }
11253 if (missing)
11254 continue;
11255
11256 for (j = 0; j < xsize; j++) {
11257 lambda = blue + j*dispersion;
11258 mdata[j] = cpl_polynomial_eval_1d(ids, lambda-reference, NULL);
11259 }
11260
11261 cpl_polynomial_delete(ids);
11262 }
11263
11264 return map;
11265
11266 }
11267
11268
11290 cpl_image *mos_map_idscoeff(cpl_table *idscoeff, int xsize, double reference,
11291 double blue, double red)
11292 {
11293 const char *func = "mos_map_idscoeff";
11294
11295 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
11296
11297
11298 cpl_polynomial *ids;
11299 cpl_image *map;
11300 float *mdata;
11301 double lambda;
11302 double c;
11303 int order;
11304 int ysize;
11305 int missing;
11306 int i, j;
11307 cpl_size k;
11308
11309
11310 if (idscoeff == NULL) {
11311 cpl_msg_error(func, "An IDS coeff table must be given");
11312 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11313 return NULL;
11314 }
11315
11316 if (xsize < 1) {
11317 cpl_msg_error(func, "Invalid image size");
11318 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11319 return NULL;
11320 }
11321
11322 if (xsize < 20 || xsize > 5000) {
11323 cpl_msg_warning(func, "Do you really have a detector %d pixels long?",
11324 xsize);
11325 }
11326
11327 ysize = cpl_table_get_nrow(idscoeff);
11328 map = cpl_image_new(xsize, ysize, CPL_TYPE_FLOAT);
11329 mdata = cpl_image_get_data(map);
11330
11331 order = 0;
11332 while (order < 6 && cpl_table_has_column(idscoeff, clab[order]))
11333 ++order;
11334 --order;
11335
11336 for (i = 0; i < ysize; i++, mdata += xsize) {
11337
11338 missing = 0;
11339 ids = cpl_polynomial_new(1);
11340 for (k = 0; k <= order; k++) {
11341 c = cpl_table_get_double(idscoeff, clab[k], i, &missing);
11342 if (missing) {
11343 cpl_polynomial_delete(ids);
11344 break;
11345 }
11346 cpl_polynomial_set_coeff(ids, &k, c);
11347 }
11348 if (missing)
11349 continue;
11350
11351 for (j = 0; j < xsize; j++) {
11352 lambda = mos_eval_dds(ids, blue, red, reference, j);
11353
11354 if (lambda >= blue && lambda <= red) {
11355 mdata[j] = lambda;
11356 }
11357 }
11358
11359 cpl_polynomial_delete(ids);
11360 }
11361
11362 return map;
11363
11364 }
11365
11366
11401 cpl_image *mos_map_wavelengths(cpl_image *spatial, cpl_image *calibration,
11402 cpl_table *slits, cpl_table *polytraces,
11403 double reference, double blue, double red,
11404 double dispersion)
11405 {
11406 const char *func = "mos_map_wavelengths";
11407
11408 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
11409
11410 cpl_polynomial *polytop;
11411 cpl_polynomial *polybot;
11412 cpl_image *remapped;
11413 float *data;
11414 float *wdata;
11415 float *sdata;
11416 float *xdata;
11417 double vtop, vbot, value;
11418 double top, bot;
11419 double coeff;
11420 double ytop, ybot;
11421 double ypos;
11422 double fvalue;
11423 int ivalue;
11424 int yint, ysize, yprev;
11425 int nslits;
11426 int npseudo;
11427 int *slit_id;
11428 int *position;
11429 int *length;
11430 int nx, ny;
11431 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
11432 int missing_top, missing_bot;
11433 int null;
11434 int order;
11435 int i, j;
11436 cpl_size k;
11437
11438
11439 if (spatial == NULL || calibration == NULL ||
11440 slits == NULL || polytraces == NULL) {
11441 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11442 return NULL;
11443 }
11444
11445 if (dispersion <= 0.0) {
11446 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11447 return NULL;
11448 }
11449
11450 if (red - blue < dispersion) {
11451 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11452 return NULL;
11453 }
11454
11455 nx = cpl_image_get_size_x(spatial);
11456 ny = cpl_image_get_size_y(spatial);
11457 ysize = cpl_image_get_size_y(calibration);
11458 remapped = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
11459 data = cpl_image_get_data(remapped);
11460 sdata = cpl_image_get_data(spatial);
11461 wdata = cpl_image_get_data(calibration);
11462
11463 nslits = cpl_table_get_nrow(slits);
11464 slit_id = cpl_table_get_data_int(slits, "slit_id");
11465 order = cpl_table_get_ncol(polytraces) - 2;
11466 position = cpl_table_get_data_int(slits, "position");
11467 length = cpl_table_get_data_int(slits, "length");
11468
11469
11470
11471
11472
11473
11474 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
11475 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
11476
11477 for (i = 0; i < nslits; i++) {
11478
11479 if (length[i] == 0)
11480 continue;
11481
11482
11483
11484
11485
11486
11487
11488
11489
11490
11491
11492
11493 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
11494
11495 start_pixel = refpixel - pixel_below;
11496 if (start_pixel < 0)
11497 start_pixel = 0;
11498
11499 end_pixel = refpixel + pixel_above;
11500 if (end_pixel > nx)
11501 end_pixel = nx;
11502
11503
11504
11505
11506
11507
11508 missing_top = 0;
11509 polytop = cpl_polynomial_new(1);
11510 for (k = 0; k <= order; k++) {
11511 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
11512 if (null) {
11513 cpl_polynomial_delete(polytop);
11514 missing_top = 1;
11515 break;
11516 }
11517 cpl_polynomial_set_coeff(polytop, &k, coeff);
11518 }
11519
11520 missing_bot = 0;
11521 polybot = cpl_polynomial_new(1);
11522 for (k = 0; k <= order; k++) {
11523 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
11524 if (null) {
11525 cpl_polynomial_delete(polybot);
11526 missing_bot = 1;
11527 break;
11528 }
11529 cpl_polynomial_set_coeff(polybot, &k, coeff);
11530 }
11531
11532 if (missing_top && missing_bot) {
11533 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
11534 slit_id[i]);
11535 continue;
11536 }
11537
11538
11539
11540
11541
11542
11543
11544 if (missing_top) {
11545 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
11546 "the spectral curvature of the lower edge "
11547 "is used instead.", slit_id[i]);
11548 polytop = cpl_polynomial_duplicate(polybot);
11549 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
11550 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
11551 k = 0;
11552 coeff = cpl_polynomial_get_coeff(polybot, &k);
11553 coeff += ytop - ybot;
11554 cpl_polynomial_set_coeff(polytop, &k, coeff);
11555 }
11556
11557 if (missing_bot) {
11558 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
11559 "the spectral curvature of the upper edge "
11560 "is used instead.", slit_id[i]);
11561 polybot = cpl_polynomial_duplicate(polytop);
11562 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
11563 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
11564 k = 0;
11565 coeff = cpl_polynomial_get_coeff(polytop, &k);
11566 coeff -= ytop - ybot;
11567 cpl_polynomial_set_coeff(polybot, &k, coeff);
11568 }
11569
11570
11571
11572
11573
11574
11575
11576
11577 xdata = wdata + nx*position[i];
11578 npseudo = length[i] - 1;
11579
11580
11581
11582
11583
11584 for (j = start_pixel; j < end_pixel; j++) {
11585 top = cpl_polynomial_eval_1d(polytop, j, NULL);
11586 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
11587 for (k = 0; k <= npseudo; k++) {
11588 ypos = top - k*(top-bot)/npseudo;
11589 yint = ypos;
11590
11591
11592
11593
11594
11595
11596
11597
11598 if (yint < 0 || yint >= ny-1) {
11599 yprev = yint;
11600 continue;
11601 }
11602
11603 value = sdata[j + nx*yint];
11604 ivalue = value;
11605 fvalue = value - ivalue;
11606 if (ivalue < npseudo && ivalue >= 0) {
11607 vtop = xdata[j + nx*(npseudo-ivalue)];
11608 vbot = xdata[j + nx*(npseudo-ivalue-1)];
11609 if (vtop < 1.0) {
11610 if (vbot < 1.0) {
11611 value = 0.0;
11612 }
11613 else {
11614 value = vbot;
11615 }
11616 }
11617 else if (vbot < 1.0) {
11618 if (k)
11619 value = vtop;
11620 else
11621 value = 0.0;
11622 }
11623 else if (fabs(vbot-vtop) > 10*dispersion) {
11624 value = 0.0;
11625 }
11626 else {
11627 value = vtop*(1-fvalue) + vbot*fvalue;
11628 }
11629 data[j + nx*yint] = value;
11630
11631 if (k) {
11632
11633
11634
11635
11636
11637
11638
11639 if (yprev - yint > 1) {
11640 value = sdata[j + nx*(yint+1)];
11641 ivalue = value;
11642 fvalue = value - ivalue;
11643 if (ivalue < npseudo && ivalue >= 0) {
11644 vtop = xdata[j + nx*(npseudo-ivalue)];
11645 vbot = xdata[j + nx*(npseudo-ivalue-1)];
11646 if (vtop < 1.0) {
11647 if (vbot < 1.0) {
11648 value = data[j + nx*(yint+1)];
11649 }
11650 else {
11651 value = vbot;
11652 }
11653 }
11654 else if (vbot < 1.0) {
11655 value = vtop;
11656 }
11657 else if (fabs(vbot-vtop) > 2*dispersion) {
11658 value = vtop;
11659 }
11660 else {
11661 value = vtop*(1-fvalue) + vbot*fvalue;
11662 }
11663 data[j + nx*(yint+1)] = value;
11664 }
11665 }
11666 }
11667 }
11668 yprev = yint;
11669 }
11670 }
11671 cpl_polynomial_delete(polytop);
11672 cpl_polynomial_delete(polybot);
11673 }
11674
11675 return remapped;
11676 }
11677
11751 cpl_image *mos_map_spectrum(cpl_image *spectra, cpl_image *wavecalib,
11752 cpl_image *spatial, cpl_table *slits,
11753 cpl_table *polytraces, double reference,
11754 double blue, double red, double dispersion,
11755 int flux)
11756 {
11757 const char *func = "mos_map_spectrum";
11758
11759 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
11760
11761 cpl_polynomial *polytop;
11762 cpl_polynomial *polybot;
11763 cpl_image *remapped;
11764 cpl_image **exslit;
11765 float *data;
11766 float *wdata;
11767 float *sdata;
11768 float *xdata;
11769 double lambda00, lambda01, lambda10, lambda11, lambda;
11770 double space00, space01, space10, space11, space;
11771 double value00, value01, value10, value11, value0, value1, value;
11772 double dL, dS;
11773 double top, bot;
11774 double coeff;
11775 double ytop, ybot;
11776 double xfrac, yfrac;
11777 int yint, ysize;
11778 int itop, ibot;
11779 int shift;
11780 int L, S;
11781 int nslits;
11782 int npseudo;
11783 int *slit_id;
11784 int *position;
11785 int *length;
11786 int nx, ny;
11787 int x, y;
11788 int nlambda;
11789 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
11790 int missing_top, missing_bot;
11791 int null;
11792 int order;
11793 int i;
11794 cpl_size k;
11795
11796
11797 flux += flux;
11798
11799 if (spectra == NULL || spatial == NULL || wavecalib == NULL ||
11800 slits == NULL || polytraces == NULL) {
11801 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
11802 return NULL;
11803 }
11804
11805 if (dispersion <= 0.0) {
11806 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11807 return NULL;
11808 }
11809
11810 if (red - blue < dispersion) {
11811 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
11812 return NULL;
11813 }
11814
11815 nx = cpl_image_get_size_x(spectra);
11816 ny = cpl_image_get_size_y(spectra);
11817
11818 if (nx != cpl_image_get_size_x(spatial) ||
11819 ny != cpl_image_get_size_y(spatial) ||
11820 nx != cpl_image_get_size_x(wavecalib) ||
11821 ny != cpl_image_get_size_y(wavecalib)) {
11822 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
11823 return NULL;
11824 }
11825
11826 nlambda = STRETCH_FACTOR * (red - blue) / dispersion;
11827 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
11828 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
11829
11830 data = cpl_image_get_data(spectra);
11831 sdata = cpl_image_get_data(spatial);
11832 wdata = cpl_image_get_data(wavecalib);
11833
11834 nslits = cpl_table_get_nrow(slits);
11835 slit_id = cpl_table_get_data_int(slits, "slit_id");
11836 order = cpl_table_get_ncol(polytraces) - 2;
11837 position = cpl_table_get_data_int(slits, "position");
11838 length = cpl_table_get_data_int(slits, "length");
11839
11840 exslit = cpl_calloc(nslits, sizeof(cpl_image *));
11841
11842 for (i = 0; i < nslits; i++) {
11843
11844 if (length == 0)
11845 continue;
11846
11847
11848
11849
11850
11851
11852
11853
11854
11855
11856
11857
11858 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
11859
11860 start_pixel = refpixel - pixel_below;
11861 if (start_pixel < 1)
11862 start_pixel = 1;
11863
11864 end_pixel = refpixel + pixel_above;
11865 if (end_pixel > nx)
11866 end_pixel = nx;
11867
11868
11869
11870
11871
11872
11873 missing_top = 0;
11874 polytop = cpl_polynomial_new(1);
11875 for (k = 0; k <= order; k++) {
11876 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
11877 if (null) {
11878 cpl_polynomial_delete(polytop);
11879 missing_top = 1;
11880 break;
11881 }
11882 cpl_polynomial_set_coeff(polytop, &k, coeff);
11883 }
11884
11885 missing_bot = 0;
11886 polybot = cpl_polynomial_new(1);
11887 for (k = 0; k <= order; k++) {
11888 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
11889 if (null) {
11890 cpl_polynomial_delete(polybot);
11891 missing_bot = 1;
11892 break;
11893 }
11894 cpl_polynomial_set_coeff(polybot, &k, coeff);
11895 }
11896
11897 if (missing_top && missing_bot) {
11898 cpl_msg_debug(func, "Slit %d was not traced: no extraction!",
11899 slit_id[i]);
11900 continue;
11901 }
11902
11903
11904
11905
11906
11907
11908
11909 if (missing_top) {
11910 cpl_msg_debug(func, "Upper edge of slit %d was not traced: "
11911 "the spectral curvature of the lower edge "
11912 "is used instead.", slit_id[i]);
11913 polytop = cpl_polynomial_duplicate(polybot);
11914 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
11915 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
11916 k = 0;
11917 coeff = cpl_polynomial_get_coeff(polybot, &k);
11918 coeff += ytop - ybot;
11919 cpl_polynomial_set_coeff(polytop, &k, coeff);
11920 }
11921
11922 if (missing_bot) {
11923 cpl_msg_debug(func, "Lower edge of slit %d was not traced: "
11924 "the spectral curvature of the upper edge "
11925 "is used instead.", slit_id[i]);
11926 polybot = cpl_polynomial_duplicate(polytop);
11927 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
11928 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
11929 k = 0;
11930 coeff = cpl_polynomial_get_coeff(polytop, &k);
11931 coeff -= ytop - ybot;
11932 cpl_polynomial_set_coeff(polybot, &k, coeff);
11933 }
11934
11935
11936
11937
11938
11939 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
11940 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
11941 npseudo = ceil(top-bot) + 1;
11942
11943 if (npseudo < 1) {
11944 cpl_polynomial_delete(polytop);
11945 cpl_polynomial_delete(polybot);
11946 cpl_msg_debug(func, "Slit %d was badly traced: no extraction!",
11947 slit_id[i]);
11948 continue;
11949 }
11950
11951 exslit[i] = cpl_image_new(nlambda, npseudo+1, CPL_TYPE_FLOAT);
11952 xdata = cpl_image_get_data(exslit[i]);
11953
11954
11955
11956
11957
11958 for (x = start_pixel; x < end_pixel; x++) {
11959 top = cpl_polynomial_eval_1d(polytop, x, NULL);
11960 bot = cpl_polynomial_eval_1d(polybot, x, NULL);
11961 itop = top + 1;
11962 ibot = bot;
11963 if (itop < 0)
11964 itop = 0;
11965 if (itop > ny - 1)
11966 itop = ny - 1;
11967 if (ibot < 0)
11968 ibot = 0;
11969 if (ibot > ny - 1)
11970 ibot = ny - 1;
11971 for (y = ibot; y < itop; y++) {
11972 lambda11 = wdata[x + y*nx];
11973 if (lambda11 < 1.0)
11974 continue;
11975 space11 = sdata[x + y*nx];
11976 if (space11 < 0.0)
11977 continue;
11978 lambda01 = wdata[x - 1 + y*nx];
11979 if (lambda01 < 1.0)
11980 continue;
11981 space01 = sdata[x - 1 + y*nx];
11982 if (space01 < 0.0)
11983 continue;
11984
11985 shift = 0;
11986
11987
11988
11989
11990
11991
11992
11993
11994
11995
11996
11997
11998
11999
12000
12001
12002
12003
12004
12005
12006
12007
12008
12009
12010
12011
12012
12013
12014 lambda10 = wdata[x + shift + (y+1)*nx];
12015 if (lambda10 < 1.0)
12016 continue;
12017 space10 = sdata[x + shift + (y+1)*nx];
12018 if (space10 < 0.0)
12019 continue;
12020 lambda00 = wdata[x - 1 + shift + (y+1)*nx];
12021 if (lambda00 < 1.0)
12022 continue;
12023 space00 = sdata[x - 1 + shift + (y+1)*nx];
12024 if (space00 < 0.0)
12025 continue;
12026
12027
12028
12029
12030
12031
12032
12033 dL = lambda11 - lambda01;
12034 dS = space11 - space10;
12035
12036
12037
12038
12039
12040
12041 L = (lambda11 - blue)/dispersion + 0.5;
12042 S = space11 + 0.5;
12043
12044 if (L < 0 || L >= nlambda)
12045 continue;
12046 if (S < 0 || S > npseudo)
12047 continue;
12048
12049
12050
12051
12052
12053 lambda = blue + L*dispersion;
12054 space = S;
12055
12056
12057
12058
12059
12060
12061
12062
12063
12064
12065 xfrac = (lambda11-lambda)/dL;
12066 yfrac = (space11-space)/dS;
12067
12068
12069
12070
12071
12072
12073
12074
12075
12076
12077 value11 = data[x + y*nx];
12078 value01 = data[x - 1 + y*nx];
12079 value10 = data[x + shift + (y+1)*nx];
12080 value00 = data[x + shift - 1 + (y+1)*nx];
12081
12082
12083
12084
12085
12086 value1 = (1-xfrac)*value11 + xfrac*value01;
12087 value0 = (1-xfrac)*value10 + xfrac*value00;
12088 value = (1-yfrac)*value1 + yfrac*value0;
12089
12090
12091
12092
12093
12094
12095 xdata[L + nlambda*(npseudo-S)] = value;
12096
12097 }
12098 }
12099 cpl_polynomial_delete(polytop);
12100 cpl_polynomial_delete(polybot);
12101 }
12102
12103
12104
12105
12106
12107 ysize = 0;
12108 for (i = 0; i < nslits; i++)
12109 if (exslit[i])
12110 ysize += cpl_image_get_size_y(exslit[i]);
12111
12112 remapped = cpl_image_new(nlambda, ysize, CPL_TYPE_FLOAT);
12113
12114 yint = -1;
12115 for (i = 0; i < nslits; i++) {
12116 if (exslit[i]) {
12117 yint += cpl_image_get_size_y(exslit[i]);
12118 cpl_image_copy(remapped, exslit[i], 1, ysize - yint);
12119 cpl_image_delete(exslit[i]);
12120 cpl_table_set_int(slits, "position", i, ysize - yint - 1);
12121 }
12122 }
12123
12124 cpl_free(exslit);
12125
12126 return remapped;
12127
12128 }
12129
12130
12163 cpl_table *mos_sky_map_super(cpl_image *spectra, cpl_image *wavemap,
12164 double dispersion, double factor, int minpoints,
12165 cpl_image *skymap)
12166 {
12167 const char *func = "mos_sky_map_super";
12168
12169 cpl_vector **vector;
12170 cpl_vector **wvector;
12171 double firstLambda, lastLambda;
12172 double lambda, lambda1, lambda2;
12173 double value, value1, value2;
12174 double frac;
12175 float min, max;
12176 int *count;
12177 int nbin, bin;
12178 int nx, ny, npix;
12179 int first_valid, valid_bins;
12180 int i, j;
12181
12182 cpl_table *sky;
12183 double *sky_spectrum;
12184 double *sky_wave;
12185 float *data;
12186 float *sdata;
12187 float *kdata;
12188
12189
12190 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
12191 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12192 return NULL;
12193 }
12194
12195 if (dispersion <= 0.0) {
12196 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12197 cpl_msg_error(func, "Negative dispersion: %s", cpl_error_get_message());
12198 return NULL;
12199 }
12200
12201 nx = cpl_image_get_size_x(spectra);
12202 ny = cpl_image_get_size_y(spectra);
12203 npix = nx * ny;
12204
12205 if (nx != cpl_image_get_size_x(wavemap) ||
12206 ny != cpl_image_get_size_y(wavemap) ||
12207 nx != cpl_image_get_size_x(skymap) ||
12208 ny != cpl_image_get_size_y(skymap)) {
12209 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
12210 cpl_msg_error(func, "Image sizes: %s", cpl_error_get_message());
12211 return NULL;
12212 }
12213
12214 if (factor < 1.0) {
12215 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12216 cpl_msg_error(func, "Undersampling (%f): %s", factor,
12217 cpl_error_get_message());
12218 return NULL;
12219 }
12220
12221 if (minpoints < 0) {
12222 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12223 cpl_msg_error(func, "Negative threshold: %s", cpl_error_get_message());
12224 return NULL;
12225 }
12226
12227 dispersion /= factor;
12228
12229
12230
12231
12232
12233
12234 data = cpl_image_get_data(wavemap);
12235
12236 for (i = 0; i < npix; i++) {
12237 if (data[i] > 1.0) {
12238 min = max = data[i];
12239 j = i+1;
12240 break;
12241 }
12242 }
12243
12244 for (i = j; i < npix; i++) {
12245 if (data[i] < 1.0)
12246 continue;
12247 if (min > data[i])
12248 min = data[i];
12249 if (max < data[i])
12250 max = data[i];
12251 }
12252
12253 firstLambda = min;
12254 lastLambda = max;
12255
12256
12257
12258
12259
12260
12261 nbin = (lastLambda - firstLambda) / dispersion;
12262
12263
12264
12265
12266
12267
12268
12269
12270 count = cpl_calloc(nbin, sizeof(int));
12271
12272 data = cpl_image_get_data(wavemap);
12273
12274 for (i = 0; i < npix; i++) {
12275 if (data[i] < 1.0)
12276 continue;
12277 bin = (data[i] - firstLambda) / dispersion;
12278 if (bin < nbin)
12279 count[bin]++;
12280 }
12281
12282 valid_bins = 0;
12283 for (i = 0; i < nbin; i++)
12284 if (count[i] >= minpoints)
12285 valid_bins++;
12286
12287 if (valid_bins < nbin/3) {
12288 cpl_msg_warning(func, "Cannot determine a good global sky "
12289 "spectrum from input data");
12290 return NULL;
12291 }
12292
12293
12294
12295
12296
12297
12298
12299
12300
12301 vector = cpl_calloc(nbin, sizeof(cpl_vector *));
12302 wvector = cpl_calloc(nbin, sizeof(cpl_vector *));
12303 for (i = 0; i < nbin; i++) {
12304 if (count[i] >= minpoints) {
12305 vector[i] = cpl_vector_new(count[i]);
12306 wvector[i] = cpl_vector_new(count[i]);
12307 }
12308 count[i] = 0;
12309 }
12310
12311
12312
12313
12314
12315
12316
12317 data = cpl_image_get_data(wavemap);
12318 sdata = cpl_image_get_data(spectra);
12319
12320 for (i = 0; i < npix; i++) {
12321 if (data[i] < 1.0)
12322 continue;
12323 bin = (data[i] - firstLambda) / dispersion;
12324 if (bin < nbin) {
12325 if (vector[bin]) {
12326 cpl_vector_set(vector[bin], count[bin], sdata[i]);
12327 cpl_vector_set(wvector[bin], count[bin], data[i]);
12328 }
12329 count[bin]++;
12330 }
12331 }
12332
12333
12334
12335
12336
12337
12338
12339 sky_spectrum = cpl_calloc(nbin, sizeof(double));
12340 sky_wave = cpl_calloc(nbin, sizeof(double));
12341 for (i = 0; i < nbin; i++) {
12342 if (vector[i]) {
12343 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
12344 sky_wave[i] = cpl_vector_get_median_const(wvector[i]);
12345 cpl_vector_delete(vector[i]);
12346 cpl_vector_delete(wvector[i]);
12347 }
12348 }
12349
12350 cpl_free(vector);
12351 cpl_free(wvector);
12352
12353
12354
12355
12356
12357
12358 for (i = 0; i < nbin; i++) {
12359 if (count[i] >= minpoints) {
12360 first_valid = i;
12361 break;
12362 }
12363 }
12364
12365 for (i = first_valid; i < nbin; i++) {
12366 if (count[i] < minpoints) {
12367 sky_wave[i] = firstLambda + (i+0.5)*dispersion;
12368 for (j = i+1; j < nbin; j++) {
12369 if (count[j] >= minpoints) {
12370 if (sky_wave[j] - sky_wave[i-1] < 0.1) {
12371 sky_spectrum[i] = (sky_spectrum[j] + sky_spectrum[i-1])
12372 / 2;
12373 }
12374 else {
12375 frac = (sky_wave[i] - sky_wave[i-1])
12376 / (sky_wave[j] - sky_wave[i-1]);
12377 sky_spectrum[i] = frac * sky_spectrum[j]
12378 + (1 - frac) * sky_spectrum[i-1];
12379 }
12380 }
12381 }
12382 }
12383 }
12384
12385
12386
12387
12388
12389
12390 sky = cpl_table_new(nbin);
12391 cpl_table_wrap_double(sky, sky_wave, "wavelength");
12392 cpl_table_wrap_double(sky, sky_spectrum, "sky");
12393 cpl_table_wrap_int(sky, count, "npoints");
12394
12395
12396
12397
12398
12399
12400 data = cpl_image_get_data(wavemap);
12401 sdata = cpl_image_get_data(spectra);
12402 kdata = cpl_image_get_data(skymap);
12403
12404 for (i = 0; i < npix; i++) {
12405
12406
12407
12408
12409
12410 lambda = data[i];
12411 if (lambda < 1.0)
12412 continue;
12413 bin = (lambda - firstLambda) / dispersion;
12414 lambda1 = sky_wave[bin];
12415 value1 = sky_spectrum[bin];
12416 if (lambda1 < lambda) {
12417 bin++;
12418 if (bin < nbin) {
12419 lambda2 = sky_wave[bin];
12420 value2 = sky_spectrum[bin];
12421 if (lambda2 - lambda1 < 0.1) {
12422 value = (value1 + value2) / 2;
12423 }
12424 else {
12425 frac = (lambda - lambda1) / (lambda2 - lambda1);
12426 value = frac * value2 + (1 - frac) * value1;
12427 }
12428 }
12429 else {
12430 value = value1;
12431 }
12432 }
12433 else {
12434 if (bin > 0) {
12435 bin--;
12436 lambda2 = lambda1;
12437 value2 = value1;
12438 lambda1 = sky_wave[bin];
12439 value1 = sky_spectrum[bin];
12440 if (lambda2 - lambda1 < 0.1) {
12441 value = (value1 + value2) / 2;
12442 }
12443 else {
12444 frac = (lambda - lambda1) / (lambda2 - lambda1);
12445 value = frac * value2 + (1 - frac) * value1;
12446 }
12447 }
12448 else {
12449 value = value1;
12450 }
12451 }
12452 kdata[i] = value;
12453 }
12454
12455 if (first_valid)
12456 cpl_table_erase_window(sky, 0, first_valid);
12457
12458 return sky;
12459
12460 }
12461
12462
12496 cpl_table *mos_sky_map(cpl_image *spectra, cpl_image *wavemap,
12497 double dispersion, cpl_image *skymap)
12498 {
12499 const char *func = "mos_sky_map";
12500
12501 cpl_vector **vector;
12502 double firstLambda, lastLambda;
12503 double lambda, lambda1, lambda2;
12504 double value, value1, value2;
12505 float min, max;
12506 int *count;
12507 int nbin, bin;
12508 int nx, ny, npix;
12509 int i, j;
12510
12511 cpl_table *sky;
12512 double *sky_spectrum;
12513 float *data;
12514 float *sdata;
12515 float *kdata;
12516 double *wdata;
12517
12518
12519 if (spectra == NULL || wavemap == NULL || skymap == NULL) {
12520 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12521 return NULL;
12522 }
12523
12524 if (dispersion <= 0.0) {
12525 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
12526 return NULL;
12527 }
12528
12529 nx = cpl_image_get_size_x(spectra);
12530 ny = cpl_image_get_size_y(spectra);
12531 npix = nx * ny;
12532
12533 if (nx != cpl_image_get_size_x(wavemap) ||
12534 ny != cpl_image_get_size_y(wavemap) ||
12535 nx != cpl_image_get_size_x(skymap) ||
12536 ny != cpl_image_get_size_y(skymap)) {
12537 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
12538 return NULL;
12539 }
12540
12541
12542
12543
12544
12545
12546 data = cpl_image_get_data(wavemap);
12547
12548 for (i = 0; i < npix; i++) {
12549 if (data[i] > 1.0) {
12550 min = max = data[i];
12551 j = i+1;
12552 break;
12553 }
12554 }
12555
12556 for (i = j; i < npix; i++) {
12557 if (data[i] < 1.0)
12558 continue;
12559 if (min > data[i])
12560 min = data[i];
12561 if (max < data[i])
12562 max = data[i];
12563 }
12564
12565 firstLambda = min;
12566 lastLambda = max;
12567
12568
12569
12570
12571
12572
12573 nbin = (lastLambda - firstLambda) / dispersion;
12574
12575
12576
12577
12578
12579
12580
12581
12582 count = cpl_calloc(nbin, sizeof(int));
12583
12584 data = cpl_image_get_data(wavemap);
12585
12586 for (i = 0; i < npix; i++) {
12587 if (data[i] < 1.0)
12588 continue;
12589 bin = (data[i] - firstLambda) / dispersion;
12590 if (bin < nbin)
12591 count[bin]++;
12592 }
12593
12594
12595
12596
12597
12598
12599
12600
12601
12602 vector = cpl_calloc(nbin, sizeof(cpl_vector *));
12603 for (i = 0; i < nbin; i++) {
12604 if (count[i])
12605 vector[i] = cpl_vector_new(count[i]);
12606 else
12607 vector[i] = NULL;
12608 count[i] = 0;
12609 }
12610
12611
12612
12613
12614
12615
12616
12617 data = cpl_image_get_data(wavemap);
12618 sdata = cpl_image_get_data(spectra);
12619
12620 for (i = 0; i < npix; i++) {
12621 if (data[i] < 1.0)
12622 continue;
12623 bin = (data[i] - firstLambda) / dispersion;
12624 if (bin < nbin) {
12625 cpl_vector_set(vector[bin], count[bin], sdata[i]);
12626 count[bin]++;
12627 }
12628 }
12629
12630
12631
12632
12633
12634
12635
12636 sky_spectrum = cpl_calloc(nbin, sizeof(double));
12637 for (i = 0; i < nbin; i++) {
12638 if (vector[i]) {
12639 sky_spectrum[i] = cpl_vector_get_median_const(vector[i]);
12640 cpl_vector_delete(vector[i]);
12641 }
12642 }
12643
12644 cpl_free(vector);
12645
12646
12647
12648
12649
12650
12651
12652
12653
12654
12655
12656
12657
12658 sky = cpl_table_new(nbin);
12659 cpl_table_new_column(sky, "wavelength", CPL_TYPE_DOUBLE);
12660 cpl_table_set_column_unit(sky, "wavelength", "pixel");
12661 cpl_table_wrap_double(sky, sky_spectrum, "sky");
12662 cpl_table_wrap_int(sky, count, "npoints");
12663 for (i = 0; i < nbin; i++)
12664 cpl_table_set_double(sky, "wavelength", i,
12665 firstLambda + (i+0.5)*dispersion);
12666
12667
12668
12669
12670
12671
12672 data = cpl_image_get_data(wavemap);
12673 sdata = cpl_image_get_data(spectra);
12674 kdata = cpl_image_get_data(skymap);
12675 wdata = cpl_table_get_data_double(sky, "wavelength");
12676
12677 for (i = 0; i < npix; i++) {
12678
12679
12680
12681
12682
12683 lambda = data[i];
12684 if (lambda < 1.0)
12685 continue;
12686 bin = (lambda - firstLambda) / dispersion;
12687 lambda1 = wdata[bin];
12688 value1 = sky_spectrum[bin];
12689 if (lambda1 < lambda) {
12690 bin++;
12691 if (bin < nbin) {
12692 lambda2 = wdata[bin];
12693 value2 = sky_spectrum[bin];
12694 value = ((lambda2 - lambda)*value1
12695 + (lambda - lambda1)*value2) / dispersion;
12696 }
12697 else {
12698 value = value1;
12699 }
12700 }
12701 else {
12702 if (bin > 0) {
12703 bin--;
12704 lambda2 = lambda1;
12705 value2 = value1;
12706 lambda1 = wdata[bin];
12707 value1 = sky_spectrum[bin];
12708 value = ((lambda2 - lambda)*value1
12709 + (lambda - lambda1)*value2)/dispersion;
12710 }
12711 else {
12712 value = value1;
12713 }
12714 }
12715 kdata[i] = value;
12716 }
12717
12718 return sky;
12719
12720 }
12721
12722
12738 cpl_image *mos_sky_local_old(cpl_image *spectra, cpl_table *slits)
12739 {
12740 const char *func = "mos_sky_local_old";
12741
12742 cpl_image *exslit;
12743 cpl_image *sky;
12744 cpl_image *skymap;
12745 float *data;
12746 float *sdata;
12747 int nx, ny;
12748 int xlow, ylow, xhig, yhig;
12749 int nslits;
12750 int *slit_id;
12751 int *position;
12752 int *length;
12753 int i, j, k;
12754
12755
12756 if (spectra == NULL) {
12757 cpl_msg_error(func,
12758 "A scientific rectified spectral image must be given");
12759 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12760 return NULL;
12761 }
12762
12763 if (slits == NULL) {
12764 cpl_msg_error(func, "A slits position table must be given");
12765 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12766 return NULL;
12767 }
12768
12769 nslits = cpl_table_get_nrow(slits);
12770 slit_id = cpl_table_get_data_int(slits, "slit_id");
12771 position = cpl_table_get_data_int(slits, "position");
12772 length = cpl_table_get_data_int(slits, "length");
12773
12774 nx = cpl_image_get_size_x(spectra);
12775 ny = cpl_image_get_size_y(spectra);
12776
12777 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12778
12779 xlow = 1;
12780 xhig = nx;
12781 for (i = 0; i < nslits; i++) {
12782
12783 if (length[i] == 0)
12784 continue;
12785
12786
12787
12788
12789
12790
12791
12792
12793
12794
12795
12796 ylow = position[i] + 1;
12797 yhig = ylow + length[i] - 1;
12798
12799 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
12800 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
12801 cpl_image_delete(exslit);
12802
12803 data = cpl_image_get_data(skymap);
12804 data += nx * position[i];
12805
12806 for (j = 0; j < length[i]; j++) {
12807 sdata = cpl_image_get_data(sky);
12808 for (k = 0; k < nx; k++) {
12809 *data++ = *sdata++;
12810 }
12811 }
12812
12813 cpl_image_delete(sky);
12814 }
12815
12816 return skymap;
12817
12818 }
12819
12820
12840 cpl_image *mos_sky_local(cpl_image *spectra, cpl_table *slits, int order)
12841 {
12842 const char *func = "mos_sky_local";
12843
12844 char name[MAX_COLNAME];
12845
12846 cpl_polynomial *fit;
12847 cpl_vector *points;
12848 cpl_vector *values;
12849 cpl_vector *keep_points;
12850 cpl_vector *keep_values;
12851 cpl_image *exslit;
12852 cpl_image *sky;
12853 cpl_image *subtracted;
12854 cpl_image *profile;
12855 cpl_image *skymap;
12856 cpl_table *objects;
12857 float *data;
12858 float *sdata;
12859 float *xdata;
12860 double *vdata;
12861 double *pdata;
12862 double median;
12863 int nx, ny;
12864 int xlow, ylow, xhig, yhig;
12865 int nslits;
12866 int *slit_id;
12867 int *position;
12868 int *length;
12869 int *is_sky;
12870 int nsky, nbad;
12871 int maxobjects;
12872 int margin = 3;
12873 int radius = 6;
12874 int i, j, k;
12875
12876
12877 if (spectra == NULL) {
12878 cpl_msg_error(func,
12879 "A scientific rectified spectral image must be given");
12880 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12881 return NULL;
12882 }
12883
12884 if (slits == NULL) {
12885 cpl_msg_error(func, "A slits position table must be given");
12886 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12887 return NULL;
12888 }
12889
12890 if (order < 0) {
12891 cpl_msg_error(func, "Invalid fit order");
12892 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
12893 return NULL;
12894 }
12895
12896 nslits = cpl_table_get_nrow(slits);
12897 slit_id = cpl_table_get_data_int(slits, "slit_id");
12898 position = cpl_table_get_data_int(slits, "position");
12899 length = cpl_table_get_data_int(slits, "length");
12900
12901 nx = cpl_image_get_size_x(spectra);
12902 ny = cpl_image_get_size_y(spectra);
12903
12904 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
12905
12906 xlow = 1;
12907 xhig = nx;
12908 for (i = 0; i < nslits; i++) {
12909
12910 if (length[i] == 0)
12911 continue;
12912
12913
12914
12915
12916
12917
12918
12919
12920
12921
12922
12923 ylow = position[i] + 1;
12924 yhig = ylow + length[i] - 1;
12925
12926 exslit = cpl_image_extract(spectra, xlow, ylow, xhig, yhig);
12927 sky = cpl_image_collapse_median_create(exslit, 0, 0, 1);
12928 cpl_image_delete(exslit);
12929
12930 data = cpl_image_get_data(skymap);
12931 data += nx * position[i];
12932
12933 for (j = 0; j < length[i]; j++) {
12934 sdata = cpl_image_get_data(sky);
12935 for (k = 0; k < nx; k++) {
12936 *data++ = *sdata++;
12937 }
12938 }
12939
12940 cpl_image_delete(sky);
12941 }
12942
12943
12944
12945
12946
12947
12948 subtracted = cpl_image_duplicate(spectra);
12949 cpl_image_subtract(subtracted, skymap);
12950 cpl_image_delete(skymap);
12951
12952
12953
12954
12955
12956
12957 objects = cpl_table_duplicate(slits);
12958 profile = mos_detect_objects(subtracted, objects, margin, radius, 0);
12959 cpl_image_delete(profile);
12960 cpl_image_delete(subtracted);
12961
12962
12963
12964
12965
12966
12967
12968 maxobjects = 1;
12969 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
12970 while (cpl_table_has_column(objects, name)) {
12971 maxobjects++;
12972 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
12973 }
12974
12975 is_sky = cpl_calloc(ny, sizeof(int));
12976
12977 for (i = 0; i < nslits; i++) {
12978
12979 if (length[i] == 0)
12980 continue;
12981
12982 ylow = position[i] + margin;
12983 yhig = position[i] + length[i] - margin;
12984
12985 for (j = ylow; j < yhig; j++)
12986 is_sky[j] = 1;
12987
12988 for (j = 1; j < maxobjects; j++) {
12989 snprintf(name, MAX_COLNAME, "object_%d", j);
12990 if (cpl_table_is_valid(objects, name, i)) {
12991 snprintf(name, MAX_COLNAME, "start_%d", j);
12992 ylow = cpl_table_get_int(objects, name, i, NULL);
12993 snprintf(name, MAX_COLNAME, "end_%d", j);
12994 yhig = cpl_table_get_int(objects, name, i, NULL);
12995 for (k = ylow; k <= yhig; k++)
12996 is_sky[k] = 0;
12997 }
12998 }
12999
13000
13001
13002
13003
13004
13005 ylow = position[i] + margin + 1;
13006 yhig = position[i] + length[i] - margin - 1;
13007
13008 for (j = ylow; j < yhig; j++)
13009 if (is_sky[j])
13010 if (is_sky[j-1] == 0 && is_sky[j+1] == 0)
13011 is_sky[j] = 0;
13012
13013 }
13014
13015
13016
13017
13018
13019
13020 skymap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
13021
13022 for (i = 0; i < nslits; i++) {
13023
13024 if (length[i] == 0)
13025 continue;
13026
13027 ylow = position[i];
13028 yhig = ylow + length[i];
13029
13030 nsky = 0;
13031 for (j = ylow; j < yhig; j++)
13032 if (is_sky[j])
13033 nsky++;
13034
13035 if (nsky > order + 1) {
13036 if (order) {
13037 points = cpl_vector_new(nsky);
13038 nsky = 0;
13039 for (j = ylow; j < yhig; j++) {
13040 if (is_sky[j]) {
13041 cpl_vector_set(points, nsky, j);
13042 nsky++;
13043 }
13044 }
13045
13046 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
13047 xdata = cpl_image_get_data(exslit);
13048 values = cpl_vector_new(nsky);
13049
13050 for (j = 0; j < nx; j++) {
13051 nsky = 0;
13052 for (k = ylow; k < yhig; k++) {
13053 if (is_sky[k]) {
13054 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
13055 nsky++;
13056 }
13057 }
13058
13059
13060
13061
13062
13063 median = cpl_vector_get_median_const(values);
13064 vdata = cpl_vector_get_data(values);
13065 pdata = cpl_vector_get_data(points);
13066 nbad = 0;
13067 for (k = 0; k < nsky; k++) {
13068 if (fabs(vdata[k] - median) < 100) {
13069 if (nbad) {
13070 vdata[k-nbad] = vdata[k];
13071 pdata[k-nbad] = pdata[k];
13072 }
13073 }
13074 else
13075 nbad++;
13076 }
13077
13078 if (nsky == nbad)
13079 continue;
13080
13081 if (nbad && nsky - nbad > order + 1) {
13082 keep_values = values;
13083 keep_points = points;
13084 values = cpl_vector_wrap(nsky-nbad, vdata);
13085 points = cpl_vector_wrap(nsky-nbad, pdata);
13086 }
13087
13088 if (nsky - nbad > order + 1) {
13089
13090 fit = cpl_polynomial_fit_1d_create(points, values,
13091 order, NULL);
13092
13093 if (fit) {
13094 for (k = ylow; k < yhig; k++) {
13095 xdata[j+(k-ylow)*nx] =
13096 cpl_polynomial_eval_1d(fit, k, NULL);
13097 }
13098
13099 cpl_polynomial_delete(fit);
13100 }
13101 else
13102 cpl_error_reset();
13103 }
13104 else {
13105 for (k = 0; k < nsky; k++) {
13106 xdata[j+k*nx] = median;
13107 }
13108 }
13109
13110 if (nbad && nsky - nbad > order + 1) {
13111 cpl_vector_unwrap(values);
13112 cpl_vector_unwrap(points);
13113 values = keep_values;
13114 points = keep_points;
13115 }
13116
13117 if (nbad) {
13118 nsky = 0;
13119 for (k = ylow; k < yhig; k++) {
13120 if (is_sky[k]) {
13121 cpl_vector_set(points, nsky, k);
13122 nsky++;
13123 }
13124 }
13125 }
13126
13127 }
13128
13129 cpl_vector_delete(values);
13130 cpl_vector_delete(points);
13131
13132 cpl_image_copy(skymap, exslit, 1, ylow+1);
13133 cpl_image_delete(exslit);
13134
13135 }
13136 else {
13137 exslit = cpl_image_extract(spectra, 1, ylow+1, nx, yhig);
13138 xdata = cpl_image_get_data(exslit);
13139 values = cpl_vector_new(nsky);
13140
13141 for (j = 0; j < nx; j++) {
13142 nsky = 0;
13143 for (k = ylow; k < yhig; k++) {
13144 if (is_sky[k]) {
13145 cpl_vector_set(values, nsky, xdata[j+(k-ylow)*nx]);
13146 nsky++;
13147 }
13148 }
13149
13150 median = cpl_vector_get_median_const(values);
13151
13152 for (k = ylow; k < yhig; k++)
13153 xdata[j+(k-ylow)*nx] = median;
13154
13155 }
13156
13157 cpl_vector_delete(values);
13158
13159 cpl_image_copy(skymap, exslit, 1, ylow+1);
13160 cpl_image_delete(exslit);
13161 }
13162 }
13163 else
13164 cpl_msg_warning(func, "Too few sky points in slit %d", i + 1);
13165 }
13166
13167 cpl_free(is_sky);
13168
13169 return skymap;
13170
13171 }
13172
13173
13195 cpl_error_code mos_clean_cosmics(cpl_image *image, float gain,
13196 float threshold, float ratio)
13197 {
13198 const char *func = "mos_clean_cosmics";
13199
13200 cpl_image *smoothImage;
13201 cpl_table *table;
13202 cpl_matrix *kernel;
13203 int *xdata;
13204 int *ydata;
13205 float *idata;
13206 float *sdata;
13207 float sigma, sum, value, smoothValue;
13208 double noise;
13209 int count;
13210 float fMax;
13211 int iMin, iMax, jMin, jMax, iPosMax, jPosMax;
13212 int xLen;
13213 int yLen;
13214 int nPix;
13215 int first = 1;
13216
13217 int pos, i, j, k, l, ii, jj, iii = 0, jjj = 0;
13218 int numCosmic = 0;
13219 int found, foundContiguousCandidate;
13220 int *cosmic;
13221
13222
13223 if (image == NULL)
13224 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13225
13226
13227
13228
13229
13230
13231
13232
13233
13234
13235
13236
13237 xLen = cpl_image_get_size_x(image);
13238 yLen = cpl_image_get_size_y(image);
13239
13240 if (xLen < 4 || yLen < 4)
13241 return CPL_ERROR_NONE;
13242
13243 nPix = xLen * yLen;
13244
13245
13246
13247
13248
13249
13250
13251
13252
13253
13254
13255
13256
13257
13258
13259
13260
13261
13262
13263
13264
13265
13266 idata = cpl_image_get_data(image);
13267 noise = 0.0;
13268 count = 0;
13269
13270 for (i = 0; i < nPix; i++) {
13271 if (idata[i] < -0.00001) {
13272 noise -= idata[i];
13273 count++;
13274 }
13275 }
13276
13277 noise /= count;
13278 noise *= 1.25;
13279
13280 cosmic = cpl_calloc(nPix, sizeof(int));
13281
13282 if (threshold < 0.)
13283 threshold = 4.0;
13284 if (ratio < 0.)
13285 ratio = 2.0;
13286
13287 kernel = cpl_matrix_new(3, 3);
13288 cpl_matrix_fill(kernel, 1.0);
13289 cpl_matrix_set(kernel, 1, 1, 0.0);
13290 smoothImage = cpl_image_filter_median(image, kernel);
13291 cpl_matrix_delete(kernel);
13292
13293
13294
13295
13296
13297
13298
13299
13300
13301
13302 sdata = cpl_image_get_data(smoothImage);
13303
13304 for (j = 1; j < yLen - 1; j++) {
13305 for (i = 1; i < xLen - 1; i++) {
13306 value = idata[i + j * xLen];
13307 smoothValue = sdata[i + j * xLen];
13308 if (smoothValue < 1.0)
13309 smoothValue = 1.0;
13310 sigma = sqrt(noise * noise + smoothValue / gain);
13311 if (value - smoothValue >= threshold * sigma)
13312 cosmic[i + j * xLen] = -1;
13313 }
13314 }
13315
13316 cpl_image_delete(smoothImage);
13317
13318
13319
13320
13321
13322
13323 do {
13324 found = 0;
13325 for (pos = first; pos < nPix; pos++) {
13326 if (cosmic[pos] == -1) {
13327 cosmic[pos] = 2;
13328 i = pos % xLen;
13329 j = pos / xLen;
13330 first = pos;
13331 first++;
13332 found = 1;
13333 break;
13334 }
13335 }
13336
13337 if (found) {
13338
13339
13340
13341
13342
13343
13344
13345
13346 iMin = iMax = iPosMax = i;
13347 jMin = jMax = jPosMax = j;
13348 fMax = idata[i + j * xLen];
13349
13350 do {
13351 foundContiguousCandidate = 0;
13352 for (l = 0; l <= 1; l++) {
13353 for (k = 0; k <= 1; k++) {
13354
13355
13356
13357
13358
13359 ii = i + k - l;
13360 jj = j + k + l - 1;
13361 if (cosmic[ii + jj * xLen] == -1) {
13362 foundContiguousCandidate = 1;
13363 cosmic[ii + jj * xLen] = 2;
13364
13365 iii = ii;
13366 jjj = jj;
13367
13368
13369
13370
13371
13372 if (ii < iMin)
13373 iMin = ii;
13374 if (ii > iMax)
13375 iMax = ii;
13376 if (jj < jMin)
13377 jMin = jj;
13378 if (jj > jMax)
13379 jMax = jj;
13380
13381 if (idata[ii + jj * xLen] > fMax) {
13382 fMax = idata[ii + jj * xLen];
13383 iPosMax = ii;
13384 jPosMax = jj;
13385 }
13386 }
13387 }
13388 }
13389
13390
13391
13392
13393
13394
13395 cosmic[i + j * xLen] = 3;
13396
13397 if (foundContiguousCandidate) {
13398
13399
13400
13401
13402
13403
13404 i = iii;
13405 j = jjj;
13406
13407
13408
13409
13410
13411 continue;
13412 }
13413
13414
13415
13416
13417
13418
13419 for (l = jMin; l <= jMax; l++) {
13420 for (k = iMin; k <= iMax; k++) {
13421 if (cosmic[k + l * xLen] == 2) {
13422 i = k;
13423 j = l;
13424 foundContiguousCandidate = 1;
13425 break;
13426 }
13427 }
13428 if (foundContiguousCandidate)
13429 break;
13430 }
13431 } while (foundContiguousCandidate);
13432
13433
13434
13435
13436
13437
13438
13439 sum = 0.;
13440 for (l = -1; l <= 1; l++) {
13441 for (k = -1; k <= 1; k++) {
13442 if (l != 0 || k != 0) {
13443 sum += idata[iPosMax + k + (jPosMax + l) * xLen];
13444 }
13445 }
13446 }
13447
13448 sum /= 8.;
13449 if (fMax > ratio * sum) {
13450 for (l = jMin - 1; l <= jMax + 1; l++) {
13451 for (k = iMin - 1; k <= iMax + 1; k++) {
13452 if (cosmic[k + l * xLen] == 3) {
13453 cosmic[k + l * xLen] = 1;
13454 numCosmic++;
13455 }
13456 }
13457 }
13458 }
13459 else {
13460 for (l = jMin - 1; l <= jMax + 1; l++) {
13461 for (k = iMin - 1; k <= iMax + 1; k++) {
13462 if (cosmic[k + l * xLen] != -1) {
13463 if (cosmic[k + l * xLen] == 1)
13464 numCosmic--;
13465 cosmic[k + l * xLen] = 0;
13466 }
13467 }
13468 }
13469 }
13470 }
13471 } while (found);
13472
13473
13474
13475
13476
13477
13478 table = cpl_table_new(numCosmic);
13479 cpl_table_new_column(table, "x", CPL_TYPE_INT);
13480 cpl_table_new_column(table, "y", CPL_TYPE_INT);
13481 cpl_table_set_column_unit(table, "x", "pixel");
13482 cpl_table_set_column_unit(table, "y", "pixel");
13483 xdata = cpl_table_get_data_int(table, "x");
13484 ydata = cpl_table_get_data_int(table, "y");
13485
13486 for (pos = 0, i = 0; pos < nPix; pos++) {
13487 if (cosmic[pos] == 1) {
13488 xdata[i] = (pos % xLen);
13489 ydata[i] = (pos / xLen);
13490 i++;
13491 }
13492 }
13493
13494 mos_clean_bad_pixels(image, table, 1);
13495
13496 cpl_free(cosmic);
13497 cpl_table_delete(table);
13498
13499 return CPL_ERROR_NONE;
13500
13501 }
13502
13503
13504 cpl_error_code mos_clean_bad_pixels(cpl_image *image, cpl_table *table,
13505 int spectral)
13506 {
13507 const char *func = "mos_clean_cosmics";
13508
13509 float *idata;
13510 int *isBadPix;
13511 int i, j, k, d;
13512 int xlen, ylen, totPix;
13513 int nBadPixels = 0;
13514 int sign, foundFirst;
13515 int *xValue = NULL;
13516 int *yValue = NULL;
13517 float save = 0.;
13518 double sumd;
13519 int cx, cy;
13520 int nPairs;
13521 float estimate[4];
13522 int sx[] = {0, 1, 1, 1};
13523 int sy[] = {1,-1, 0, 1};
13524 int searchHorizon = 100;
13525 int percent = 15;
13526
13527
13528 if (image == NULL || table == NULL)
13529 return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13530
13531 if (1 != cpl_table_has_column(table, "x"))
13532 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
13533
13534 if (1 != cpl_table_has_column(table, "y"))
13535 return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
13536
13537 if (CPL_TYPE_INT != cpl_table_get_column_type(table, "x"))
13538 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
13539
13540 if (CPL_TYPE_INT != cpl_table_get_column_type(table, "y"))
13541 return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
13542
13543 nBadPixels = cpl_table_get_nrow(table);
13544
13545 if (nBadPixels) {
13546 xlen = cpl_image_get_size_x(image);
13547 ylen = cpl_image_get_size_y(image);
13548 idata = cpl_image_get_data(image);
13549 totPix = xlen * ylen;
13550 if (((float) nBadPixels) / ((float) totPix) < percent/100.) {
13551 isBadPix = cpl_calloc(totPix, sizeof(int));
13552 }
13553 else {
13554 cpl_msg_warning(func, "Too many bad pixels (> %d%%): "
13555 "skip bad pixel correction", percent);
13556 return cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13557 }
13558 }
13559 else {
13560 cpl_msg_debug(func, "No pixel values to interpolate");
13561 return CPL_ERROR_NONE;
13562 }
13563
13564 xValue = cpl_table_get_data_int(table, "x");
13565 yValue = cpl_table_get_data_int(table, "y");
13566
13567 for (i = 0; i < nBadPixels; i++)
13568 isBadPix[xValue[i] + yValue[i] * xlen] = 1;
13569
13570 for (i = 0; i < nBadPixels; i++) {
13571
13572
13573
13574
13575
13576
13577
13578
13579
13580
13581
13582
13583
13584 nPairs = 0;
13585 for (j = 0; j < 4; j++) {
13586
13587 if (spectral)
13588 if (j != 2)
13589 continue;
13590
13591 estimate[nPairs] = 0.;
13592 sumd = 0.;
13593 foundFirst = 0;
13594 for (k = 0; k < 2; k++) {
13595 sign = 2 * k - 1;
13596 d = 0;
13597 cx = xValue[i];
13598 cy = yValue[i];
13599 do {
13600 cx += sign * sx[j];
13601 cy += sign * sy[j];
13602 if (cx < 0 || cx >= xlen || cy < 0 || cy >= ylen)
13603 break;
13604 d++;
13605 } while (isBadPix[cx + cy * xlen] && d < searchHorizon);
13606
13607 if (cx >= 0 && cx < xlen &&
13608 cy >= 0 && cy < ylen && d < searchHorizon) {
13609
13610
13611
13612
13613
13614 save = idata[cx + cy * xlen];
13615 estimate[nPairs] += save / d;
13616 sumd += 1. / (double) d;
13617 if (k) {
13618 estimate[nPairs] /= sumd;
13619 nPairs++;
13620 }
13621 else {
13622 foundFirst = 1;
13623 }
13624 }
13625 else {
13626
13627
13628
13629
13630
13631 if (k) {
13632 if (foundFirst) {
13633 estimate[nPairs] = save;
13634 nPairs++;
13635 }
13636 }
13637 }
13638 }
13639 }
13640
13641
13642
13643
13644
13645
13646
13647 if (nPairs > 2) {
13648 idata[xValue[i] + yValue[i] * xlen] =
13649 cpl_tools_get_median_float(estimate, nPairs);
13650 }
13651 else if (nPairs == 2) {
13652 idata[xValue[i] + yValue[i] * xlen] =
13653 (estimate[0] + estimate[1]) / 2.;
13654 }
13655 else if (nPairs == 1) {
13656 idata[xValue[i] + yValue[i] * xlen] = estimate[0];
13657 }
13658 else {
13659 cpl_msg_debug(func, "Cannot correct bad pixel %d,%d\n",
13660 xValue[i], yValue[i]);
13661 }
13662 }
13663
13664 cpl_free(isBadPix);
13665
13666 return CPL_ERROR_NONE;
13667 }
13668
13669
13699 cpl_image *mos_spatial_map(cpl_image *spectra, cpl_table *slits,
13700 cpl_table *polytraces, double reference,
13701 double blue, double red, double dispersion)
13702 {
13703 const char *func = "mos_spatial_map";
13704
13705 const char *clab[6] = {"c0", "c1", "c2", "c3", "c4", "c5"};
13706
13707 cpl_polynomial *polytop;
13708 cpl_polynomial *polybot;
13709 cpl_image *calibration;
13710 float *data;
13711 double top, bot;
13712 double coeff;
13713 double ytop, ybot;
13714 double ypos, yfra;
13715 double factor;
13716 int yint, yprev;
13717 int nslits;
13718 int npseudo;
13719 int *slit_id;
13720 int *length;
13721 int nx, ny;
13722 int pixel_above, pixel_below, refpixel, start_pixel, end_pixel;
13723 int missing_top, missing_bot;
13724 int null;
13725 int order;
13726 int i, j;
13727 cpl_size k;
13728
13729
13730 if (spectra == NULL || slits == NULL || polytraces == NULL) {
13731 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
13732 return NULL;
13733 }
13734
13735 if (dispersion <= 0.0) {
13736 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13737 return NULL;
13738 }
13739
13740 if (red - blue < dispersion) {
13741 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
13742 return NULL;
13743 }
13744
13745 nx = cpl_image_get_size_x(spectra);
13746 ny = cpl_image_get_size_y(spectra);
13747
13748 calibration = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
13749 data = cpl_image_get_data(calibration);
13750
13751 length = cpl_table_get_data_int(slits, "length");
13752 nslits = cpl_table_get_nrow(slits);
13753 slit_id = cpl_table_get_data_int(slits, "slit_id");
13754 order = cpl_table_get_ncol(polytraces) - 2;
13755
13756
13757
13758
13759
13760
13761 pixel_above = STRETCH_FACTOR * (red - reference) / dispersion;
13762 pixel_below = STRETCH_FACTOR * (reference - blue) / dispersion;
13763
13764 for (i = 0; i < nslits; i++) {
13765
13766 if (length[i] == 0)
13767 continue;
13768
13769
13770
13771
13772
13773
13774
13775
13776
13777
13778
13779
13780 refpixel = cpl_table_get_double(slits, "xtop", i, NULL);
13781
13782 start_pixel = refpixel - pixel_below;
13783 if (start_pixel < 0)
13784 start_pixel = 0;
13785
13786 end_pixel = refpixel + pixel_above;
13787 if (end_pixel > nx)
13788 end_pixel = nx;
13789
13790
13791
13792
13793
13794
13795 missing_top = 0;
13796 polytop = cpl_polynomial_new(1);
13797 for (k = 0; k <= order; k++) {
13798 coeff = cpl_table_get_double(polytraces, clab[k], 2*i, &null);
13799 if (null) {
13800 cpl_polynomial_delete(polytop);
13801 missing_top = 1;
13802 break;
13803 }
13804 cpl_polynomial_set_coeff(polytop, &k, coeff);
13805 }
13806
13807 missing_bot = 0;
13808 polybot = cpl_polynomial_new(1);
13809 for (k = 0; k <= order; k++) {
13810 coeff = cpl_table_get_double(polytraces, clab[k], 2*i+1, &null);
13811 if (null) {
13812 cpl_polynomial_delete(polybot);
13813 missing_bot = 1;
13814 break;
13815 }
13816 cpl_polynomial_set_coeff(polybot, &k, coeff);
13817 }
13818
13819 if (missing_top && missing_bot) {
13820 cpl_msg_warning(func, "Spatial map, slit %d was not traced!",
13821 slit_id[i]);
13822 continue;
13823 }
13824
13825
13826
13827
13828
13829
13830
13831 if (missing_top) {
13832 cpl_msg_warning(func, "Upper edge of slit %d was not traced: "
13833 "the spectral curvature of the lower edge "
13834 "is used instead.", slit_id[i]);
13835 polytop = cpl_polynomial_duplicate(polybot);
13836 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
13837 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
13838 k = 0;
13839 coeff = cpl_polynomial_get_coeff(polybot, &k);
13840 coeff += ytop - ybot;
13841 cpl_polynomial_set_coeff(polytop, &k, coeff);
13842 }
13843
13844 if (missing_bot) {
13845 cpl_msg_warning(func, "Lower edge of slit %d was not traced: "
13846 "the spectral curvature of the upper edge "
13847 "is used instead.", slit_id[i]);
13848 polybot = cpl_polynomial_duplicate(polytop);
13849 ytop = cpl_table_get_double(slits, "ytop", i, NULL);
13850 ybot = cpl_table_get_double(slits, "ybottom", i, NULL);
13851 k = 0;
13852 coeff = cpl_polynomial_get_coeff(polytop, &k);
13853 coeff -= ytop - ybot;
13854 cpl_polynomial_set_coeff(polybot, &k, coeff);
13855 }
13856
13857 top = cpl_polynomial_eval_1d(polytop, refpixel, NULL);
13858 bot = cpl_polynomial_eval_1d(polybot, refpixel, NULL);
13859 npseudo = ceil(top-bot) + 1;
13860
13861 if (npseudo < 1) {
13862 cpl_polynomial_delete(polytop);
13863 cpl_polynomial_delete(polybot);
13864 cpl_msg_warning(func, "Slit %d was badly traced: no extraction!",
13865 slit_id[i]);
13866 continue;
13867 }
13868
13869 for (j = start_pixel; j < end_pixel; j++) {
13870 top = cpl_polynomial_eval_1d(polytop, j, NULL);
13871 bot = cpl_polynomial_eval_1d(polybot, j, NULL);
13872 factor = (top-bot)/npseudo;
13873 for (k = 0; k <= npseudo; k++) {
13874 ypos = top - k*factor;
13875 yint = ypos;
13876 yfra = ypos - yint;
13877 if (yint >= 0 && yint < ny-1) {
13878 data[j + nx*yint] = (top-yint)/factor;
13879 if (k) {
13880
13881
13882
13883
13884
13885
13886
13887 if (yprev - yint > 1) {
13888 data[j + nx*(yint+1)] = (top-yint-1)/factor;
13889 }
13890 }
13891 }
13892 yprev = yint;
13893 }
13894 }
13895 cpl_polynomial_delete(polytop);
13896 cpl_polynomial_delete(polybot);
13897 }
13898
13899 return calibration;
13900 }
13901
13902
13965 cpl_image *mos_detect_objects(cpl_image *image, cpl_table *slits, int margin,
13966 int maxradius, int conradius)
13967 {
13968 const char *func = "mos_detect_objects";
13969
13970 cpl_image *profile;
13971 float *pdata;
13972 float *p;
13973
13974 char name[MAX_COLNAME];
13975
13976 int nslits;
13977 int npeaks;
13978 int nobjects, objpos, totobj;
13979 int maxobjects;
13980 int *position;
13981 int *length;
13982 int *reject;
13983 double *place;
13984 double *bright;
13985 double mindistance;
13986 int pos, count;
13987 int up;
13988 int low, hig;
13989 int row;
13990 int i, j, k;
13991
13992 const int min_pixels = 10;
13993
13994
13995 if (cpl_error_get_code() != CPL_ERROR_NONE)
13996 return NULL;
13997
13998 if (image == NULL || slits == NULL) {
13999 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14000 return NULL;
14001 }
14002
14003 if (margin < 0)
14004 margin = 0;
14005
14006 if (maxradius < 0) {
14007 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14008 return NULL;
14009 }
14010
14011 if (conradius < 0) {
14012 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14013 return NULL;
14014 }
14015
14016 nslits = cpl_table_get_nrow(slits);
14017 position = cpl_table_get_data_int(slits, "position");
14018 length = cpl_table_get_data_int(slits, "length");
14019
14020 profile = cpl_image_collapse_create(image, 1);
14021 cpl_image_divide_scalar(profile, cpl_image_get_size_x(image));
14022 pdata = cpl_image_get_data(profile);
14023
14024 row = 1;
14025 maxobjects = 0;
14026 totobj = 0;
14027 for (i = 0; i < nslits; i++) {
14028
14029 if (length[i] == 0)
14030 continue;
14031
14032 pos = position[i] + margin;
14033 count = length[i] - 2*margin;
14034
14035 if (count < min_pixels)
14036 continue;
14037
14038 p = pdata + pos;
14039
14040
14041
14042
14043
14044
14045 npeaks = 0;
14046 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
14047 npeaks++;
14048 }
14049
14050 up = 0;
14051 for (j = 0; j < count - 3; j++) {
14052 if (p[j] > 0) {
14053 if (p[j+1] > p[j]) {
14054 up++;
14055 }
14056 else {
14057 if (up > 2) {
14058 if (p[j+1] > p[j+2] && p[j+2] > 0) {
14059 if (p[j] > 5)
14060 npeaks++;
14061 }
14062 }
14063 else if (up > 1) {
14064 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
14065 if (p[j] > 5)
14066 npeaks++;
14067 }
14068 }
14069 up = 0;
14070 }
14071 }
14072 else {
14073 up = 0;
14074 }
14075 }
14076
14077 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
14078 && p[count-3] > p[count-4] && p[count-4] > 0) {
14079 npeaks++;
14080 }
14081
14082 if (npeaks == 0)
14083 continue;
14084
14085
14086
14087
14088
14089
14090 reject = cpl_calloc(npeaks, sizeof(int));
14091 bright = cpl_calloc(npeaks, sizeof(double));
14092 place = cpl_calloc(npeaks, sizeof(double));
14093
14094 npeaks = 0;
14095 if (p[0] > p[1] && p[1] > p[2] && p[2] > p[3] && p[3] > 0) {
14096 bright[0] = p[0];
14097 place[0] = position[i] + margin;
14098 npeaks++;
14099 }
14100
14101 up = 0;
14102 for (j = 0; j < count - 3; j++) {
14103 if (p[j] > 0) {
14104 if (p[j+1] > p[j]) {
14105 up++;
14106 }
14107 else {
14108 if (up > 2) {
14109 if (p[j+1] > p[j+2] && p[j+2] > 0) {
14110 if (p[j] > 5) {
14111 bright[npeaks] = p[j];
14112 place[npeaks] = position[i] + margin + j + 1
14113 + values_to_dx(p[j-1], p[j], p[j+1]);
14114 npeaks++;
14115 }
14116 }
14117 }
14118 else if (up > 1) {
14119 if (p[j+1] > p[j+2] && p[j+2] > p[j+3] && p[j+3] > 0) {
14120 if (p[j] > 5) {
14121 bright[npeaks] = p[j];
14122 place[npeaks] = position[i] + margin + j + 1
14123 + values_to_dx(p[j-1], p[j], p[j+1]);
14124 npeaks++;
14125 }
14126 }
14127 }
14128 up = 0;
14129 }
14130 }
14131 else {
14132 up = 0;
14133 }
14134 }
14135
14136 if (p[count-1] > p[count-2] && p[count-2] > p[count-3]
14137 && p[count-3] > p[count-4] && p[count-4] > 0) {
14138 bright[npeaks] = p[count-1];
14139 place[npeaks] = position[i] + count;
14140 npeaks++;
14141 }
14142
14143
14144
14145
14146
14147
14148 if (fabs(place[0] - pos) < 1.0)
14149 reject[0] = 1;
14150 if (fabs(place[npeaks-1] - pos - count) < 1.0)
14151 reject[npeaks-1] = 1;
14152 for (j = 0; j < npeaks; j++) {
14153 for (k = 0; k < npeaks; k++) {
14154 if (k == j)
14155 continue;
14156 mindistance = conradius * bright[k] / bright[j]
14157 * bright[k] / bright[j];
14158 if (fabs(place[j] - place[k]) < mindistance)
14159 reject[j] = 1;
14160 }
14161 }
14162
14163
14164 for (j = 0; j < npeaks; j++) {
14165 if (reject[j])
14166 continue;
14167 if (j) {
14168 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
14169 / (bright[j-1] + bright[j]) + 1;
14170 }
14171 else {
14172 low = pos;
14173 }
14174 if (j < npeaks - 1) {
14175 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
14176 / (bright[j+1] + bright[j]) + 1;
14177 }
14178 else {
14179 hig = pos + count;
14180 }
14181
14182 if (low < pos)
14183 low = pos;
14184 if (hig > pos + count)
14185 hig = pos + count;
14186 if (place[j] - low > maxradius)
14187 low = place[j] - maxradius;
14188 if (hig - place[j] > maxradius)
14189 hig = place[j] + maxradius;
14190 if (hig == low)
14191 reject[j] = 1;
14192 }
14193
14194
14195 nobjects = npeaks;
14196 for (j = 0; j < npeaks; j++)
14197 if (reject[j])
14198 nobjects--;
14199
14200 for (j = 0; j < nobjects; j++) {
14201 snprintf(name, MAX_COLNAME, "object_%d", j+1);
14202 if (cpl_table_has_column(slits, name))
14203 continue;
14204 cpl_table_new_column(slits, name, CPL_TYPE_DOUBLE);
14205 snprintf(name, MAX_COLNAME, "start_%d", j+1);
14206 cpl_table_new_column(slits, name, CPL_TYPE_INT);
14207 cpl_table_set_column_unit(slits, name, "pixel");
14208 snprintf(name, MAX_COLNAME, "end_%d", j+1);
14209 cpl_table_new_column(slits, name, CPL_TYPE_INT);
14210 cpl_table_set_column_unit(slits, name, "pixel");
14211 snprintf(name, MAX_COLNAME, "row_%d", j+1);
14212 cpl_table_new_column(slits, name, CPL_TYPE_INT);
14213 cpl_table_set_column_unit(slits, name, "pixel");
14214 }
14215
14216 objpos = nobjects;
14217 for (j = 0; j < npeaks; j++) {
14218 if (reject[j])
14219 continue;
14220 if (j) {
14221 low = (place[j-1]*bright[j] + place[j]*bright[j-1])
14222 / (bright[j-1] + bright[j]) + 1;
14223 }
14224 else {
14225 low = pos;
14226 }
14227 if (j < npeaks - 1) {
14228 hig = (place[j+1]*bright[j] + place[j]*bright[j+1])
14229 / (bright[j+1] + bright[j]) + 1;
14230 }
14231 else {
14232 hig = pos + count;
14233 }
14234
14235 if (low < pos)
14236 low = pos;
14237 if (hig > pos + count)
14238 hig = pos + count;
14239 if (place[j] - low > maxradius)
14240 low = place[j] - maxradius;
14241 if (hig - place[j] > maxradius)
14242 hig = place[j] + maxradius;
14243
14244 snprintf(name, MAX_COLNAME, "object_%d", objpos);
14245 cpl_table_set_double(slits, name, i, place[j]);
14246 snprintf(name, MAX_COLNAME, "start_%d", objpos);
14247 cpl_table_set_int(slits, name, i, low);
14248 snprintf(name, MAX_COLNAME, "end_%d", objpos);
14249 cpl_table_set_int(slits, name, i, hig);
14250 snprintf(name, MAX_COLNAME, "row_%d", objpos);
14251 cpl_table_set_int(slits, name, i, row + objpos - 1);
14252 totobj++;
14253 objpos--;
14254 }
14255
14256 row += nobjects;
14257
14258 if (maxobjects < nobjects)
14259 maxobjects = nobjects;
14260
14261 cpl_free(reject);
14262 cpl_free(bright);
14263 cpl_free(place);
14264
14265 }
14266
14267
14268 row = cpl_table_get_nrow(slits);
14269
14270 for (i = 0; i < row; i++) {
14271 for (j = 0; j < maxobjects; j++) {
14272 snprintf(name, MAX_COLNAME, "row_%d", j+1);
14273 if (cpl_table_is_valid(slits, name, i))
14274 cpl_table_set_int(slits, name, i, totobj -
14275 cpl_table_get_int(slits, name, i, NULL));
14276 }
14277 }
14278
14279 for (i = 0; i < maxobjects; i++) {
14280 snprintf(name, MAX_COLNAME, "start_%d", i+1);
14281 cpl_table_fill_invalid_int(slits, name, -1);
14282 snprintf(name, MAX_COLNAME, "end_%d", i+1);
14283 cpl_table_fill_invalid_int(slits, name, -1);
14284 snprintf(name, MAX_COLNAME, "row_%d", i+1);
14285 cpl_table_fill_invalid_int(slits, name, -1);
14286 }
14287
14288 return profile;
14289 }
14290
14291
14316 cpl_image **mos_extract_objects(cpl_image *science, cpl_image *science_var,
14317 cpl_image *sky,
14318 cpl_table *objects, int extraction, double ron,
14319 double gain, int ncombined)
14320 {
14321 const char *func = "mos_extract_objects";
14322
14323 char name[MAX_COLNAME];
14324
14325 cpl_image **output;
14326 cpl_image *extracted;
14327 cpl_image *extr_sky;
14328 cpl_image *error;
14329 cpl_image *sciwin;
14330 cpl_image *sci_var_win = NULL;
14331 cpl_image *skywin;
14332 int nslits;
14333 int nobjects;
14334 int maxobjects;
14335 int nx;
14336 int ylow, yhig;
14337 int i, j;
14338
14339
14340 if (science == NULL || sky == NULL) {
14341 cpl_msg_error(func, "Both scientific exposures are required in input");
14342 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14343 return NULL;
14344 }
14345
14346 if (objects == NULL) {
14347 cpl_msg_error(func, "An object table is required in input");
14348 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14349 return NULL;
14350 }
14351
14352 if (extraction < 0 || extraction > 1) {
14353 cpl_msg_error(func, "Invalid extraction mode (%d): it should be "
14354 "either 0 or 1", extraction);
14355 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14356 return NULL;
14357 }
14358
14359 if (ron < 0.0) {
14360 cpl_msg_error(func, "Invalid read-out-noise (%f ADU)", ron);
14361 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14362 return NULL;
14363 }
14364
14365 if (gain < 0.1) {
14366 cpl_msg_error(func, "Invalid gain factor (%f e-/ADU)", gain);
14367 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14368 return NULL;
14369 }
14370
14371 if (ncombined < 1) {
14372 cpl_msg_error(func, "Invalid number of combined frames (%d): "
14373 "it should be at least 1", ncombined);
14374 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14375 return NULL;
14376 }
14377
14378
14379
14380
14381
14382
14383
14384 maxobjects = 1;
14385 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
14386 while (cpl_table_has_column(objects, name)) {
14387 maxobjects++;
14388 snprintf(name, MAX_COLNAME, "object_%d", maxobjects);
14389 }
14390
14391
14392
14393
14394
14395
14396 nobjects = 0;
14397 nslits = cpl_table_get_nrow(objects);
14398
14399 for (i = 0; i < nslits; i++) {
14400 for (j = 1; j < maxobjects; j++) {
14401 snprintf(name, MAX_COLNAME, "object_%d", j);
14402 if (cpl_table_is_valid(objects, name, i))
14403 nobjects++;
14404 }
14405 }
14406
14407 if (nobjects == 0)
14408 return NULL;
14409
14410 nx = cpl_image_get_size_x(science);
14411
14412 output = cpl_calloc(3, sizeof(cpl_image *));
14413 extracted = output[0] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
14414 extr_sky = output[1] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
14415 error = output[2] = cpl_image_new(nx, nobjects, CPL_TYPE_FLOAT);
14416
14417
14418
14419
14420
14421
14422 nobjects = 0;
14423 for (i = 0; i < nslits; i++) {
14424 for (j = 1; j < maxobjects; j++) {
14425 snprintf(name, MAX_COLNAME, "object_%d", j);
14426 if (cpl_table_is_valid(objects, name, i)) {
14427 snprintf(name, MAX_COLNAME, "start_%d", j);
14428 ylow = cpl_table_get_int(objects, name, i, NULL);
14429 snprintf(name, MAX_COLNAME, "end_%d", j);
14430 yhig = cpl_table_get_int(objects, name, i, NULL);
14431 snprintf(name, MAX_COLNAME, "row_%d", j);
14432 nobjects = cpl_table_get_int(objects, name, i, NULL);
14433 sciwin = cpl_image_extract(science, 1, ylow+1, nx, yhig);
14434 if(science_var != NULL)
14435 sci_var_win = cpl_image_extract(science_var, 1, ylow+1, nx, yhig);
14436 skywin = cpl_image_extract(sky, 1, ylow+1, nx, yhig);
14437
14438
14439
14440
14441
14442
14443
14444
14445 mos_extraction(sciwin, sci_var_win, skywin, extracted, extr_sky, error,
14446 nobjects, extraction, ron, gain, ncombined);
14447
14448
14449
14450
14451
14452 {
14453 cpl_image *total = cpl_image_add_create(sciwin, skywin);
14454 float *data = cpl_image_get_data_float(total);
14455 int size = cpl_image_get_size_x(total)
14456 * cpl_image_get_size_y(total);
14457 int k;
14458 char *saturation_level = getenv("SATURATION_LEVEL");
14459 float saturation = 62000.0;
14460 char *max_saturated = getenv("MAX_SATURATED");
14461 int max_satur = 10;
14462 int saturated;
14463
14464 if (saturation_level)
14465 saturation = atof(saturation_level);
14466
14467 if (max_saturated)
14468 max_satur = atoi(max_saturated);
14469
14470 saturated = 0;
14471 for (k = 0; k < size; k++) {
14472 if (data[k] > saturation) {
14473 saturated++;
14474 if (saturated > max_satur) {
14475 break;
14476 }
14477 }
14478 }
14479
14480 if (saturated > max_satur)
14481 saturated = 1;
14482 else
14483 saturated = 0;
14484
14485 data = cpl_image_get_data(extracted);
14486 data[nobjects * nx] = saturated;
14487 }
14488
14489 cpl_image_delete(sciwin);
14490 cpl_image_delete(skywin);
14491 nobjects++;
14492 }
14493 }
14494 }
14495
14496 return output;
14497
14498 }
14499
14500
14523 int mos_spectral_resolution(cpl_image *image, double lambda, double startwave,
14524 double dispersion, int saturation,
14525 double *mfwhm, double *rmsfwhm,
14526 double *resolution, double *rmsres, int *nlines)
14527 {
14528 cpl_vector *vector;
14529
14530 int i, j, n, m;
14531 int position, maxpos;
14532 int xlen, ylen;
14533 int sp, ep;
14534 int radius;
14535 int sradius = 40;
14536 int threshold = 250;
14537
14538 int ifwhm;
14539 double fwhm;
14540 double *buffer;
14541 double min, max, halfmax;
14542 double cut = 1.5;
14543 double value, rms;
14544
14545 float *data;
14546
14547
14548 *resolution = 0.0;
14549 *rmsres = 0.0;
14550 *nlines = 0;
14551
14552 xlen = cpl_image_get_size_x(image);
14553 ylen = cpl_image_get_size_y(image);
14554 data = cpl_image_get_data(image);
14555
14556 buffer = cpl_malloc(ylen * sizeof(double));
14557
14558
14559
14560
14561
14562 position = floor((lambda - startwave) / dispersion + 0.5);
14563
14564 sp = position - sradius;
14565 ep = position + sradius;
14566
14567 if (sp < 0 || ep > xlen) {
14568 cpl_free(buffer);
14569 return 0;
14570 }
14571
14572 for (i = 0, n = 0; i < ylen; i++) {
14573
14574
14575
14576
14577
14578 radius = mos_lines_width(data + i*xlen + position - sradius,
14579 2*sradius + 1);
14580 if (radius < 5)
14581 radius = 5;
14582
14583 sp = position - radius;
14584 ep = position + radius;
14585
14586 if (sp < 0 || ep > xlen) {
14587 cpl_free(buffer);
14588 return 0;
14589 }
14590
14591
14592
14593
14594
14595
14596 maxpos = sp;
14597 min = max = data[sp + i * xlen];
14598 for (j = sp; j < ep; j++) {
14599 if (data[j + i * xlen] > max) {
14600 max = data[j + i * xlen];
14601 maxpos = j;
14602 }
14603 if (data[j + i * xlen] < min) {
14604 min = data[j + i * xlen];
14605 }
14606 }
14607
14608 if (fabs(min) < 0.0000001)
14609 continue;
14610
14611 if (max - min < threshold)
14612 continue;
14613
14614 if (max > saturation)
14615 continue;
14616
14617
14618
14619
14620
14621
14622
14623
14624 halfmax = (max + min)/ 2.0;
14625
14626 fwhm = 0.0;
14627 ifwhm = 0;
14628 for (j = maxpos; j < maxpos + radius; j++) {
14629 if (j < xlen) {
14630 if (data[j + i * xlen] < halfmax) {
14631 fwhm = ifwhm + (data[j - 1 + i * xlen] - halfmax)
14632 / (data[j - 1 + i * xlen] - data[j + i * xlen]);
14633 break;
14634 }
14635 ifwhm++;
14636 }
14637 }
14638
14639 ifwhm = 0;
14640 for (j = maxpos; j > maxpos - radius; j--) {
14641 if (j >= 0) {
14642 if (data[j + i * xlen] < halfmax) {
14643 fwhm += ifwhm + (data[j + 1 + i * xlen] - halfmax)
14644 / (data[j + 1 + i * xlen] - data[j + i * xlen]);
14645 break;
14646 }
14647 ifwhm++;
14648 }
14649 }
14650
14651 if (fwhm > 3.0) {
14652 buffer[n] = fwhm - 2.0;
14653 n++;
14654 }
14655
14656 }
14657
14658 if (n == 0) {
14659 cpl_free(buffer);
14660 return 0;
14661 }
14662
14663 vector = cpl_vector_wrap(n, buffer);
14664 value = cpl_vector_get_median_const(vector);
14665 cpl_vector_unwrap(vector);
14666
14667 rms = 0.0;
14668 for (i = 0, m = 0; i < n; i++) {
14669 if (fabs(buffer[i] - value) < cut) {
14670 rms += fabs(buffer[i] - value);
14671 m++;
14672 }
14673 }
14674
14675 cpl_free(buffer);
14676
14677 if (m < 3)
14678 return 0;
14679
14680 rms /= m;
14681 rms *= 1.25;
14682
14683 value *= dispersion;
14684 rms *= dispersion;
14685
14686 *mfwhm = value;
14687 *rmsfwhm = rms;
14688
14689 *resolution = lambda / value;
14690 *rmsres = *resolution * rms / value;
14691
14692 *nlines = m;
14693
14694 return 1;
14695 }
14696
14697
14719 cpl_table *mos_resolution_table(cpl_image *image, double startwave,
14720 double dispersion, int saturation,
14721 cpl_vector *lines)
14722 {
14723
14724 cpl_table *table;
14725 double *line;
14726 double fwhm;
14727 double rmsfwhm;
14728 double resolution;
14729 double rmsres;
14730 int nref;
14731 int nlines;
14732 int i;
14733
14734
14735 nref = cpl_vector_get_size(lines);
14736 line = cpl_vector_get_data(lines);
14737
14738 table = cpl_table_new(nref);
14739 cpl_table_new_column(table, "wavelength", CPL_TYPE_DOUBLE);
14740 cpl_table_set_column_unit(table, "wavelength", "Angstrom");
14741 cpl_table_new_column(table, "fwhm", CPL_TYPE_DOUBLE);
14742 cpl_table_set_column_unit(table, "fwhm", "Angstrom");
14743 cpl_table_new_column(table, "fwhm_rms", CPL_TYPE_DOUBLE);
14744 cpl_table_set_column_unit(table, "fwhm_rms", "Angstrom");
14745 cpl_table_new_column(table, "resolution", CPL_TYPE_DOUBLE);
14746 cpl_table_new_column(table, "resolution_rms", CPL_TYPE_DOUBLE);
14747 cpl_table_new_column(table, "nlines", CPL_TYPE_INT);
14748
14749 for (i = 0; i < nref; i++) {
14750 if (mos_spectral_resolution(image, line[i], startwave, dispersion,
14751 saturation, &fwhm, &rmsfwhm,
14752 &resolution, &rmsres, &nlines)) {
14753 cpl_table_set_double(table, "wavelength", i, line[i]);
14754 cpl_table_set_double(table, "fwhm", i, fwhm);
14755 cpl_table_set_double(table, "fwhm_rms", i, rmsfwhm);
14756 cpl_table_set_double(table, "resolution", i, resolution);
14757 cpl_table_set_double(table, "resolution_rms", i, rmsres);
14758 cpl_table_set_int(table, "nlines", i, nlines);
14759 }
14760 else
14761 cpl_table_set_int(table, "nlines", i, 0);
14762 }
14763
14764 if (cpl_table_has_valid(table, "wavelength"))
14765 return table;
14766
14767 cpl_table_delete(table);
14768
14769 return NULL;
14770
14771 }
14772
14773
14791 double mos_integrate_signal(cpl_image *image, cpl_image *wavemap,
14792 int ystart, int yend, double wstart, double wend)
14793 {
14794 const char *func = "mos_integrate_signal";
14795
14796 double sum;
14797 float *sdata;
14798 float *wdata;
14799 int nx, ny;
14800 int x, y;
14801
14802
14803 if (image == NULL || wavemap == NULL) {
14804 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14805 return 0.0;
14806 }
14807
14808 if (ystart > yend || wstart >= wend) {
14809 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14810 return 0.0;
14811 }
14812
14813 nx = cpl_image_get_size_x(image);
14814 ny = cpl_image_get_size_y(image);
14815
14816 if (!(nx == cpl_image_get_size_x(wavemap)
14817 && ny == cpl_image_get_size_y(wavemap))) {
14818 cpl_error_set(func, CPL_ERROR_INCOMPATIBLE_INPUT);
14819 return 0.0;
14820 }
14821
14822 if (ystart < 0 || yend > ny) {
14823 cpl_error_set(func, CPL_ERROR_ACCESS_OUT_OF_RANGE);
14824 return 0.0;
14825 }
14826
14827 sdata = cpl_image_get_data(image);
14828 wdata = cpl_image_get_data(wavemap);
14829
14830 sdata += ystart*nx;
14831 wdata += ystart*nx;
14832
14833 sum = 0.0;
14834 for (y = ystart; y < yend; y++) {
14835 for (x = 0; x < nx; x++) {
14836 if (wdata[x] < wstart || wdata[x] > wend)
14837 continue;
14838 sum += sdata[x];
14839 }
14840 sdata += nx;
14841 wdata += nx;
14842 }
14843
14844 return sum;
14845
14846 }
14847
14848
14849
14850
14851
14852
14853
14854
14855
14856
14879 cpl_table *mos_load_slits_fors_mxu(cpl_propertylist *header)
14880 {
14881 const char *func = "mos_load_slits_fors_mxu";
14882
14883 cpl_table *slits;
14884 char keyname[MAX_COLNAME];
14885 const char *instrume;
14886 const char *target_name;
14887 float slit_x;
14888 float slit_y;
14889 float length;
14890 float slit_width;
14891
14892 double arc2mm = 0.528;
14893 int nslits;
14894 int slit_id;
14895 int fors;
14896 int chip;
14897 int found;
14898
14899
14900
14901
14902
14903
14904
14905 float low_limit1 = 10.0;
14906 float hig_limit2 = 30.0;
14907
14908
14909 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14910 return NULL;
14911 }
14912
14913 if (header == NULL) {
14914 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
14915 return NULL;
14916 }
14917
14918
14919
14920
14921
14922
14923 instrume = cpl_propertylist_get_string(header, "INSTRUME");
14924
14925 fors = 0;
14926 if (instrume[4] == '1')
14927 fors = 1;
14928 if (instrume[4] == '2')
14929 fors = 2;
14930
14931 if (fors != 2) {
14932 cpl_msg_error(func, "Wrong instrument: %s\n"
14933 "FORS2 is expected for MXU data", instrume);
14934 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14935 return NULL;
14936 }
14937
14938
14939
14940
14941
14942
14943
14944
14945 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
14946
14947 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14948 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
14949 "in FITS header");
14950 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14951 return NULL;
14952 }
14953
14954 if (chip != 1 && chip != 2) {
14955 cpl_msg_error(func, "Unexpected chip position in keyword "
14956 "ESO DET CHIP1 Y: %d", chip);
14957 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
14958 return NULL;
14959 }
14960
14961
14962
14963
14964
14965
14966
14967 nslits = 0;
14968 slit_id = 0;
14969 found = 1;
14970
14971 while (found) {
14972 slit_id++;
14973 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d YPOS", slit_id + 100);
14974 if (cpl_propertylist_has(header, keyname)) {
14975 slit_y = cpl_propertylist_get_double(header, keyname);
14976
14977 if (chip == 1)
14978 if (slit_y < low_limit1)
14979 continue;
14980 if (chip == 2)
14981 if (slit_y > hig_limit2)
14982 continue;
14983
14984 snprintf(keyname, MAX_COLNAME, "ESO INS TARG%d NAME",
14985 slit_id + 100);
14986 if (cpl_propertylist_has(header, keyname)) {
14987 target_name = cpl_propertylist_get_string(header, keyname);
14988 if (strncmp(target_name, "refslit", 7))
14989 nslits++;
14990 }
14991 else
14992 nslits++;
14993 }
14994 else
14995 found = 0;
14996 }
14997
14998 if (cpl_error_get_code() != CPL_ERROR_NONE) {
14999 cpl_msg_error(func, "%s while loading slits coordinates from "
15000 "FITS header", cpl_error_get_message());
15001 cpl_error_set_where(func);
15002 return NULL;
15003 }
15004
15005 if (nslits == 0) {
15006 cpl_msg_error(func, "No slits coordinates found in header");
15007 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15008 return NULL;
15009 }
15010
15011 slits = cpl_table_new(nslits);
15012 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
15013 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
15014 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
15015 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
15016 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
15017 cpl_table_new_column(slits, "xwidth", CPL_TYPE_DOUBLE);
15018 cpl_table_set_column_unit(slits, "xtop", "pixel");
15019 cpl_table_set_column_unit(slits, "ytop", "pixel");
15020 cpl_table_set_column_unit(slits, "xbottom", "pixel");
15021 cpl_table_set_column_unit(slits, "ybottom", "pixel");
15022 cpl_table_set_column_unit(slits, "xwidth" , "mm");
15023
15024 nslits = 0;
15025 slit_id = 0;
15026 found = 1;
15027 while (found) {
15028 slit_id++;
15029 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d YPOS", slit_id + 100);
15030 if (cpl_propertylist_has(header, keyname)) {
15031 slit_y = cpl_propertylist_get_double(header, keyname);
15032
15033 if (chip == 1)
15034 if (slit_y < low_limit1)
15035 continue;
15036 if (chip == 2)
15037 if (slit_y > hig_limit2)
15038 continue;
15039
15040
15041
15042
15043
15044
15045 slit_y = -slit_y;
15046
15047 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d XPOS", slit_id + 100);
15048 slit_x = cpl_propertylist_get_double(header, keyname);
15049 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15050 cpl_table_delete(slits);
15051 cpl_msg_error(func, "Missing keyword %s in FITS header",
15052 keyname);
15053 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15054 return NULL;
15055 }
15056
15057 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d LEN", slit_id + 100);
15058 length = cpl_propertylist_get_double(header, keyname);
15059 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15060 cpl_table_delete(slits);
15061 cpl_msg_error(func, "Missing keyword %s in FITS header",
15062 keyname);
15063 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15064 return NULL;
15065 }
15066
15067 length *= arc2mm;
15068
15069 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d WIDTH", slit_id + 100);
15070 slit_width = cpl_propertylist_get_double(header, keyname);
15071 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15072 cpl_table_delete(slits);
15073 cpl_msg_error(func, "Missing keyword %s in FITS header",
15074 keyname);
15075 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15076 return NULL;
15077 }
15078
15079 snprintf(keyname, MAX_COLNAME, "ESO INS TARG%d NAME",
15080 slit_id + 100);
15081 if (cpl_propertylist_has(header, keyname)) {
15082 target_name = cpl_propertylist_get_string(header, keyname);
15083 if (strncmp(target_name, "refslit", 7)) {
15084 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
15085 cpl_table_set(slits, "xtop", nslits, slit_x);
15086 cpl_table_set(slits, "ytop", nslits, slit_y + length/2);
15087 cpl_table_set(slits, "xbottom", nslits, slit_x);
15088 cpl_table_set(slits, "ybottom", nslits, slit_y - length/2);
15089 cpl_table_set(slits, "xwidth", nslits, slit_width);
15090 nslits++;
15091 }
15092 }
15093 else {
15094 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
15095 cpl_table_set(slits, "xtop", nslits, slit_x);
15096 cpl_table_set(slits, "ytop", nslits, slit_y + length/2);
15097 cpl_table_set(slits, "xbottom", nslits, slit_x);
15098 cpl_table_set(slits, "ybottom", nslits, slit_y - length/2);
15099 cpl_table_set(slits, "xwidth", nslits, slit_width);
15100 nslits++;
15101 }
15102 }
15103 else
15104 found = 0;
15105 }
15106
15107 return slits;
15108 }
15109
15110
15134 cpl_table *mos_load_slits_fors_mos(cpl_propertylist *header,
15135 int * nslits_out_det)
15136 {
15137 const char *func = "mos_load_slits_fors_mos";
15138
15139 cpl_table *slits;
15140 char keyname[MAX_COLNAME];
15141 const char *instrume;
15142 const char *chipname;
15143 float slit_x;
15144 int first_slit, last_slit;
15145 cpl_size nslits;
15146 int slit_id;
15147 int fors;
15148 int chip;
15149 int fors_is_old;
15150
15151
15152
15153
15154
15155 float ytop[19] = { 113.9, 101.3, 89.9, 77.3, 65.9, 53.3,
15156 41.9, 29.3, 17.9, 5.3, -6.1, -18.7,
15157 -30.1, -42.7, -54.1, -66.7, -78.1, -90.7,
15158 -102.1 };
15159 float ybottom[19] = { 102.1, 90.7, 78.1, 66.7, 54.1, 42.7,
15160 30.1, 18.7, 6.1, -5.3, -17.9, -29.3,
15161 -41.9, -53.3, -65.9, -77.3, -89.9, -101.3,
15162 -113.9 };
15163
15164
15165 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15166 return NULL;
15167 }
15168
15169 if (header == NULL) {
15170 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15171 return NULL;
15172 }
15173
15174
15175
15176
15177
15178
15179 instrume = cpl_propertylist_get_string(header, "INSTRUME");
15180
15181 fors = 0;
15182 if (instrume[4] == '1')
15183 fors = 1;
15184 if (instrume[4] == '2')
15185 fors = 2;
15186
15187 if (fors == 0) {
15188 cpl_msg_error(func, "Wrong instrument found in FITS header: %s",
15189 instrume);
15190 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15191 return NULL;
15192 }
15193
15194
15195
15196
15197
15198
15199
15200 chipname = cpl_propertylist_get_string(header, "ESO DET CHIP1 ID");
15201
15202 if (chipname[0] == 'M' || chipname[0] == 'N')
15203 fors_is_old = 0;
15204 else
15205 fors_is_old = 1;
15206
15207 if (fors == 1 && fors_is_old) {
15208 first_slit = 1;
15209 last_slit = 19;
15210 }
15211 else {
15212
15213
15214
15215
15216
15217
15218
15219 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
15220
15221 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15222 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
15223 "in FITS header");
15224 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15225 return NULL;
15226 }
15227
15228 if (chip != 1 && chip != 2) {
15229 cpl_msg_error(func, "Unexpected chip position in keyword "
15230 "ESO DET CHIP1 Y: %d", chip);
15231 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15232 return NULL;
15233 }
15234
15235 if (chip == 1) {
15236 first_slit = 12;
15237 last_slit = 19;
15238 }
15239 else {
15240 first_slit = 1;
15241 last_slit = 11;
15242 }
15243 }
15244
15245
15246
15247
15248
15249
15250
15251
15252 nslits = 0;
15253 slit_id = 0;
15254 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
15255 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d POS", slit_id);
15256 if (cpl_propertylist_has(header, keyname)) {
15257 slit_x = cpl_propertylist_get_double(header, keyname);
15258 if (fabs(slit_x) < 115.0)
15259 nslits++;
15260 else
15261 (*nslits_out_det)++;
15262 }
15263 else {
15264 cpl_msg_error(func, "Missing keyword %s in FITS header", keyname);
15265 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15266 return NULL;
15267 }
15268 }
15269
15270 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15271 cpl_msg_error(func, "%s while loading slits coordinates from "
15272 "FITS header", cpl_error_get_message());
15273 cpl_error_set_where(func);
15274 return NULL;
15275 }
15276
15277 if (nslits == 0) {
15278 cpl_msg_error(func, "No slits coordinates found in header");
15279 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15280 return NULL;
15281 }
15282
15283 slits = cpl_table_new(nslits);
15284 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
15285 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
15286 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
15287 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
15288 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
15289 cpl_table_new_column(slits, "xwidth", CPL_TYPE_DOUBLE);
15290 cpl_table_set_column_unit(slits, "xtop", "pixel");
15291 cpl_table_set_column_unit(slits, "ytop", "pixel");
15292 cpl_table_set_column_unit(slits, "xbottom", "pixel");
15293 cpl_table_set_column_unit(slits, "ybottom", "pixel");
15294 cpl_table_set_column_unit(slits, "xwidth" , "mm");
15295
15296 nslits = 0;
15297 slit_id = 0;
15298 for (slit_id = first_slit; slit_id <= last_slit; slit_id++) {
15299 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d POS", slit_id);
15300 slit_x = cpl_propertylist_get_double(header, keyname);
15301 if (fabs(slit_x) < 115.0) {
15302 cpl_table_set_int(slits, "slit_id", nslits, slit_id);
15303 cpl_table_set(slits, "xtop", nslits, slit_x);
15304 cpl_table_set(slits, "ytop", nslits, ytop[slit_id-1]);
15305 cpl_table_set(slits, "xbottom", nslits, slit_x);
15306 cpl_table_set(slits, "ybottom", nslits, ybottom[slit_id-1]);
15307 snprintf(keyname, MAX_COLNAME, "ESO INS MOS%d WIDTH", slit_id);
15308 double slit_width = cpl_propertylist_get_double(header, keyname);
15309 cpl_table_set(slits, "xwidth", nslits, slit_width);
15310 nslits++;
15311 }
15312 }
15313
15314 return slits;
15315 }
15316
15317
15341 cpl_table *mos_load_slits_fors_lss(cpl_propertylist *header)
15342 {
15343 const char *func = "mos_load_slits_fors_lss";
15344
15345 cpl_table *slits;
15346 char *slit_name;
15347 const char *instrume;
15348 int fors;
15349 int chip;
15350 float ytop;
15351 float ybottom;
15352
15353 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15354 return NULL;
15355 }
15356
15357 if (header == NULL) {
15358 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15359 return NULL;
15360 }
15361
15362
15363
15364
15365
15366
15367 instrume = cpl_propertylist_get_string(header, "INSTRUME");
15368
15369 fors = 0;
15370 if (instrume[4] == '1')
15371 fors = 1;
15372 if (instrume[4] == '2')
15373 fors = 2;
15374
15375 if (fors == 0) {
15376 cpl_msg_error(func, "Wrong instrument found in FITS header: %s",
15377 instrume);
15378 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15379 return NULL;
15380 }
15381
15382 if (fors == 1) {
15383 ytop = 109.94;
15384 ybottom = -109.94;
15385 }
15386 else {
15387
15388
15389
15390
15391
15392
15393
15394 chip = cpl_propertylist_get_int(header, "ESO DET CHIP1 Y");
15395
15396 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15397 cpl_msg_error(func, "Missing keyword ESO DET CHIP1 Y "
15398 "in FITS header");
15399 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15400 return NULL;
15401 }
15402
15403 if (chip != 1 && chip != 2) {
15404 cpl_msg_error(func, "Unexpected chip position in keyword "
15405 "ESO DET CHIP1 Y: %d", chip);
15406 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15407 return NULL;
15408 }
15409
15410 if (chip == 1) {
15411 ytop = 30.0;
15412 ybottom = -109.94;
15413 }
15414 else {
15415 ytop = 109.94;
15416 ybottom = -20.0;
15417 }
15418 }
15419
15420
15421 slits = cpl_table_new(1);
15422 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
15423 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
15424 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
15425 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
15426 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
15427 cpl_table_set_column_unit(slits, "xtop", "pixel");
15428 cpl_table_set_column_unit(slits, "ytop", "pixel");
15429 cpl_table_set_column_unit(slits, "xbottom", "pixel");
15430 cpl_table_set_column_unit(slits, "ybottom", "pixel");
15431
15432 slit_name = (char *)cpl_propertylist_get_string(header,
15433 "ESO INS SLIT NAME");
15434
15435 cpl_table_set(slits, "ytop", 0, ytop);
15436 cpl_table_set(slits, "ybottom", 0, ybottom);
15437
15438 if (!strncmp(slit_name, "lSlit0_3arcsec", 14)) {
15439 cpl_table_set_int(slits, "slit_id", 0, 1);
15440 cpl_table_set(slits, "xbottom", 0, -0.075);
15441 cpl_table_set(slits, "xtop", 0, 0.075);
15442 }
15443 else if (!strncmp(slit_name, "lSlit0_4arcsec", 14)) {
15444 cpl_table_set_int(slits, "slit_id", 0, 2);
15445 cpl_table_set(slits, "xbottom", 0, 5.895);
15446 cpl_table_set(slits, "xtop", 0, 6.105);
15447 }
15448 else if (!strncmp(slit_name, "lSlit0_5arcsec", 14)) {
15449 cpl_table_set_int(slits, "slit_id", 0, 3);
15450 cpl_table_set(slits, "xbottom", 0, -6.135);
15451 cpl_table_set(slits, "xtop", 0, -5.865);
15452 }
15453 else if (!strncmp(slit_name, "lSlit0_7arcsec", 14)) {
15454 cpl_table_set_int(slits, "slit_id", 0, 4);
15455 cpl_table_set(slits, "xbottom", 0, 11.815);
15456 cpl_table_set(slits, "xtop", 0, 12.185);
15457 }
15458 else if (!strncmp(slit_name, "lSlit1_0arcsec", 14)) {
15459 cpl_table_set_int(slits, "slit_id", 0, 5);
15460 cpl_table_set(slits, "xbottom", 0, -12.265);
15461 cpl_table_set(slits, "xtop", 0, -11.735);
15462 }
15463 else if (!strncmp(slit_name, "lSlit1_3arcsec", 14)) {
15464 cpl_table_set_int(slits, "slit_id", 0, 6);
15465 cpl_table_set(slits, "xbottom", 0, 17.655);
15466 cpl_table_set(slits, "xtop", 0, 18.345);
15467 }
15468 else if (!strncmp(slit_name, "lSlit1_6arcsec", 14)) {
15469 cpl_table_set_int(slits, "slit_id", 0, 7);
15470 cpl_table_set(slits, "xbottom", 0, -18.425);
15471 cpl_table_set(slits, "xtop", 0, -17.575);
15472 }
15473 else if (!strncmp(slit_name, "lSlit2_0arcsec", 14)) {
15474 cpl_table_set_int(slits, "slit_id", 0, 8);
15475 cpl_table_set(slits, "xbottom", 0, 23.475);
15476 cpl_table_set(slits, "xtop", 0, 24.525);
15477 }
15478 else if (!strncmp(slit_name, "lSlit2_5arcsec", 14)) {
15479 cpl_table_set_int(slits, "slit_id", 0, 9);
15480 cpl_table_set(slits, "xbottom", 0, -24.66);
15481 cpl_table_set(slits, "xtop", 0, -23.34);
15482 }
15483 else {
15484 cpl_msg_error(func, "Invalid slit %s in keyword ESO INS SLIT NAME",
15485 slit_name);
15486 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
15487 cpl_table_delete(slits);
15488 return NULL;
15489 }
15490
15491 return slits;
15492 }
15493
15494
15509 double mos_get_gain_vimos(cpl_propertylist *header)
15510 {
15511 const char *func = "mos_get_gain_vimos";
15512
15513 double gain = -1.0;
15514
15515
15516 if (cpl_error_get_code() != CPL_ERROR_NONE)
15517 return gain;
15518
15519 if (header == NULL) {
15520 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15521 return gain;
15522 }
15523
15524 gain = cpl_propertylist_get_double(header, "ESO DET OUT1 CONAD");
15525 if (cpl_error_get_code()) {
15526 cpl_error_set_where(func);
15527 gain = -1.0;
15528 }
15529
15530 return gain;
15531
15532 }
15533
15534
15554 cpl_table *mos_load_slits_vimos(cpl_propertylist *header)
15555 {
15556 const char *func = "mos_load_slits_vimos";
15557
15558 cpl_table *slits;
15559 char keyname[MAX_COLNAME];
15560 float slit_x;
15561 float slit_y;
15562 float dim_x;
15563 float dim_y;
15564 int nslits;
15565 int slit_id;
15566 int curved;
15567 int i;
15568
15569
15570 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15571 return NULL;
15572 }
15573
15574 if (header == NULL) {
15575 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15576 return NULL;
15577 }
15578
15579 nslits = cpl_propertylist_get_int(header, "ESO INS SLIT NO");
15580
15581 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15582 cpl_error_set_where(func);
15583 return NULL;
15584 }
15585
15586 slits = cpl_table_new(nslits);
15587 cpl_table_new_column(slits, "slit_id", CPL_TYPE_INT);
15588 cpl_table_new_column(slits, "xtop", CPL_TYPE_DOUBLE);
15589 cpl_table_new_column(slits, "ytop", CPL_TYPE_DOUBLE);
15590 cpl_table_new_column(slits, "xbottom", CPL_TYPE_DOUBLE);
15591 cpl_table_new_column(slits, "ybottom", CPL_TYPE_DOUBLE);
15592 cpl_table_new_column(slits, "xwidth", CPL_TYPE_DOUBLE);
15593 cpl_table_new_column(slits, "ywidth", CPL_TYPE_DOUBLE);
15594 cpl_table_new_column(slits, "curved", CPL_TYPE_INT);
15595 cpl_table_set_column_unit(slits, "xtop", "pixel");
15596 cpl_table_set_column_unit(slits, "ytop", "pixel");
15597 cpl_table_set_column_unit(slits, "xbottom", "pixel");
15598 cpl_table_set_column_unit(slits, "ybottom", "pixel");
15599 cpl_table_set_column_unit(slits, "xwidth", "mm");
15600 cpl_table_set_column_unit(slits, "ywidth", "mm");
15601
15602 for (i = 0; i < nslits; i++) {
15603 sprintf(keyname, "ESO INS SLIT%d ID", i+1);
15604 slit_id = cpl_propertylist_get_int(header, keyname);
15605 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15606 cpl_error_set_where(func);
15607 return NULL;
15608 }
15609 sprintf(keyname, "ESO INS SLIT%d X", i+1);
15610 slit_x = cpl_propertylist_get_double(header, keyname);
15611 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15612 cpl_error_set_where(func);
15613 return NULL;
15614 }
15615 sprintf(keyname, "ESO INS SLIT%d Y", i+1);
15616 slit_y = cpl_propertylist_get_double(header, keyname);
15617 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15618 cpl_error_set_where(func);
15619 return NULL;
15620 }
15621 sprintf(keyname, "ESO INS SLIT%d DIMX", i+1);
15622 dim_x = cpl_propertylist_get_double(header, keyname);
15623 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15624 cpl_error_set_where(func);
15625 return NULL;
15626 }
15627
15628 sprintf(keyname, "ESO INS SLIT%d BEZIER DY", i+1);
15629 if (cpl_propertylist_has(header, keyname)) {
15630 curved = 1;
15631 }
15632 else {
15633 sprintf(keyname, "ESO INS SLIT%d DIMY", i+1);
15634 curved = 0;
15635 }
15636 dim_y = cpl_propertylist_get_double(header, keyname);
15637 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15638 cpl_error_set_where(func);
15639 return NULL;
15640 }
15641
15642 cpl_table_set_int(slits, "slit_id", i, slit_id);
15643 cpl_table_set(slits, "xtop", i, slit_x - dim_x/2);
15644 cpl_table_set(slits, "ytop", i, slit_y);
15645 cpl_table_set(slits, "xbottom", i, slit_x + dim_x/2);
15646 cpl_table_set(slits, "ybottom", i, slit_y);
15647 cpl_table_set(slits, "xwidth", i, dim_x);
15648 cpl_table_set(slits, "ywidth", i, dim_y);
15649 cpl_table_set_int(slits, "curved", i, curved);
15650 }
15651
15652 return slits;
15653 }
15654
15655
15665 int mos_check_multiplex(cpl_table *slits)
15666 {
15667 cpl_propertylist *sort;
15668 int nrow;
15669 int i, multiplex, xprev, xcur;
15670 double prev, cur;
15671 double tolerance = 1.0;
15672
15673
15674
15675
15676
15677
15678
15679
15680
15681 sort = cpl_propertylist_new();
15682 cpl_propertylist_append_bool(sort, "xtop", 0);
15683 cpl_table_sort(slits, sort);
15684 cpl_propertylist_delete(sort);
15685
15686 prev = cpl_table_get_double(slits, "xtop", 0, NULL);
15687 cpl_table_new_column(slits, "xind", CPL_TYPE_INT);
15688 cpl_table_set_int(slits, "xind", 0, prev);
15689 nrow = cpl_table_get_nrow(slits);
15690 for (i = 1; i < nrow; i++) {
15691 cur = cpl_table_get_double(slits, "xtop", i, NULL);
15692 if (fabs(prev - cur) > tolerance)
15693 prev = cur;
15694 cpl_table_set_int(slits, "xind", i, prev);
15695 }
15696
15697
15698
15699
15700
15701
15702 sort = cpl_propertylist_new();
15703 cpl_propertylist_append_bool(sort, "xind", 0);
15704 cpl_propertylist_append_bool(sort, "ytop", 0);
15705 cpl_table_sort(slits, sort);
15706 cpl_propertylist_delete(sort);
15707
15708
15709
15710
15711
15712 multiplex = 0;
15713 cpl_table_new_column(slits, "multiplex", CPL_TYPE_INT);
15714 xprev = cpl_table_get_int(slits, "xind", 0, NULL);
15715 cpl_table_set_int(slits, "multiplex", 0, multiplex);
15716 nrow = cpl_table_get_nrow(slits);
15717 for (i = 1; i < nrow; i++) {
15718 xcur = cpl_table_get_int(slits, "xind", i, NULL);
15719 if (xcur == xprev) {
15720 multiplex++;
15721 }
15722 else {
15723 xprev = xcur;
15724 multiplex = 0;
15725 }
15726 cpl_table_set_int(slits, "multiplex", i, multiplex);
15727 }
15728
15729 cpl_table_save(slits, NULL, NULL, "multiplex.fits", CPL_IO_DEFAULT);
15730
15731 cpl_table_erase_column(slits, "xind");
15732
15733 return 1 + cpl_table_get_column_max(slits, "multiplex");
15734
15735 }
15736
15737
15764 cpl_table *mos_load_overscans_vimos(const cpl_propertylist *header,
15765 int check_consistency)
15766 {
15767 const char *func = "mos_load_overscans_vimos";
15768
15769 int nx = 0;
15770 int ny = 0;
15771 int px = 0;
15772 int py = 0;
15773 int ox = 0;
15774 int oy = 0;
15775 int vx = 0;
15776 int vy = 0;
15777 int nrows;
15778 cpl_table *overscans;
15779
15780
15781 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15782 cpl_msg_error(func, "Reset your error: %s", cpl_error_get_message());
15783 return NULL;
15784 }
15785
15786 if (header == NULL) {
15787 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15788 return NULL;
15789 }
15790
15791 if (cpl_propertylist_has(header, "NAXIS1"))
15792 nx = cpl_propertylist_get_int(header, "NAXIS1");
15793 if (cpl_propertylist_has(header, "NAXIS2"))
15794 ny = cpl_propertylist_get_int(header, "NAXIS2");
15795 if (cpl_propertylist_has(header, "ESO DET OUT1 PRSCX"))
15796 px = cpl_propertylist_get_int(header, "ESO DET OUT1 PRSCX");
15797 if (cpl_propertylist_has(header, "ESO DET OUT1 PRSCY"))
15798 py = cpl_propertylist_get_int(header, "ESO DET OUT1 PRSCY");
15799 if (cpl_propertylist_has(header, "ESO DET OUT1 OVSCX"))
15800 ox = cpl_propertylist_get_int(header, "ESO DET OUT1 OVSCX");
15801 if (cpl_propertylist_has(header, "ESO DET OUT1 OVSCY"))
15802 oy = cpl_propertylist_get_int(header, "ESO DET OUT1 OVSCY");
15803 if (cpl_propertylist_has(header, "ESO DET OUT1 NX"))
15804 vx = cpl_propertylist_get_int(header, "ESO DET OUT1 NX");
15805 if (cpl_propertylist_has(header, "ESO DET OUT1 NY"))
15806 vy = cpl_propertylist_get_int(header, "ESO DET OUT1 NY");
15807
15808 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15809 cpl_msg_error(func, "Missing overscan keywords in header");
15810 cpl_error_set_where(func);
15811 return NULL;
15812 }
15813
15814 if (px < 0 || py < 0 || ox < 0 || oy < 0) {
15815 cpl_msg_error(func, "Missing overscan keywords in header");
15816 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15817 return NULL;
15818 }
15819
15820 if ((px + vx + ox != nx) || (py + vy + oy != ny)) {
15821 if (check_consistency) {
15822 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15823 return NULL;
15824 }
15825 else {
15826 cpl_msg_debug(func, "Overscans description conflicts with "
15827 "reported image sizes, "
15828 "%d + %d + %d != %d or "
15829 "%d + %d + %d != %d",
15830 px, vx, ox, nx,
15831 py, vy, oy, ny);
15832 }
15833 }
15834
15835 nrows = 0;
15836 if (px > 0)
15837 nrows++;
15838 if (ox > 0)
15839 nrows++;
15840 if (py > 0)
15841 nrows++;
15842 if (oy > 0)
15843 nrows++;
15844
15845 if (nrows > 2) {
15846 cpl_msg_error(func, "Unexpected overscan regions "
15847 "(both in X and Y direction)");
15848 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
15849 return NULL;
15850 }
15851
15852
15853
15854
15855
15856
15857
15858 nrows++;
15859
15860 overscans = cpl_table_new(nrows);
15861 cpl_table_new_column(overscans, "xlow", CPL_TYPE_INT);
15862 cpl_table_new_column(overscans, "ylow", CPL_TYPE_INT);
15863 cpl_table_new_column(overscans, "xhig", CPL_TYPE_INT);
15864 cpl_table_new_column(overscans, "yhig", CPL_TYPE_INT);
15865
15866 nrows = 0;
15867
15868 cpl_table_set_int(overscans, "xlow", nrows, px);
15869 cpl_table_set_int(overscans, "ylow", nrows, py);
15870 cpl_table_set_int(overscans, "xhig", nrows, nx - ox);
15871 cpl_table_set_int(overscans, "yhig", nrows, ny - oy);
15872 nrows++;
15873
15874 if (px > 0) {
15875 cpl_table_set_int(overscans, "xlow", nrows, 0);
15876 cpl_table_set_int(overscans, "ylow", nrows, 0);
15877 cpl_table_set_int(overscans, "xhig", nrows, px);
15878 cpl_table_set_int(overscans, "yhig", nrows, ny);
15879 nrows++;
15880 }
15881
15882 if (ox > 0) {
15883 cpl_table_set_int(overscans, "xlow", nrows, nx - ox);
15884 cpl_table_set_int(overscans, "ylow", nrows, 0);
15885 cpl_table_set_int(overscans, "xhig", nrows, nx);
15886 cpl_table_set_int(overscans, "yhig", nrows, ny);
15887 nrows++;
15888 }
15889
15890 if (py > 0) {
15891 cpl_table_set_int(overscans, "xlow", nrows, 0);
15892 cpl_table_set_int(overscans, "ylow", nrows, 0);
15893 cpl_table_set_int(overscans, "xhig", nrows, nx);
15894 cpl_table_set_int(overscans, "yhig", nrows, py);
15895 nrows++;
15896 }
15897
15898 if (oy > 0) {
15899 cpl_table_set_int(overscans, "xlow", nrows, 0);
15900 cpl_table_set_int(overscans, "ylow", nrows, ny - oy);
15901 cpl_table_set_int(overscans, "xhig", nrows, nx);
15902 cpl_table_set_int(overscans, "yhig", nrows, ny);
15903 nrows++;
15904 }
15905
15906 return overscans;
15907
15908 }
15909
15910
15911 cpl_table *mos_load_overscans_fors(const cpl_propertylist *header)
15912 {
15913 const char *func = "mos_load_overscans_fors";
15914
15915 int nports;
15916 int nx = 0;
15917 int ny = 0;
15918 int px = 0;
15919 int py = 0;
15920 int ox = 0;
15921 int oy = 0;
15922 int rebin;
15923 int nrows;
15924 cpl_table *overscans;
15925
15926
15927 if (cpl_error_get_code() != CPL_ERROR_NONE) {
15928 cpl_msg_error(func, "Reset your error: %s", cpl_error_get_message());
15929 return NULL;
15930 }
15931
15932 if (header == NULL) {
15933 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
15934 return NULL;
15935 }
15936
15937 if (cpl_propertylist_has(header, "ESO DET OUTPUTS"))
15938 nports = cpl_propertylist_get_int(header, "ESO DET OUTPUTS");
15939
15940 if (nports == 4 &&
15941 cpl_propertylist_has(header, "ESO DET OUT1 PRSCX") &&
15942 cpl_propertylist_has(header, "ESO DET WIN1 BINX")) {
15943
15944 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
15945
15946 overscans = cpl_table_new(3);
15947 cpl_table_new_column(overscans, "xlow", CPL_TYPE_INT);
15948 cpl_table_new_column(overscans, "ylow", CPL_TYPE_INT);
15949 cpl_table_new_column(overscans, "xhig", CPL_TYPE_INT);
15950 cpl_table_new_column(overscans, "yhig", CPL_TYPE_INT);
15951
15952 px = 16 / rebin;
15953 ox = 16 / rebin;
15954 nx = 2080 / rebin;
15955 ny = 2048 / rebin;
15956 nrows = 0;
15957
15958 cpl_table_set_int(overscans, "xlow", nrows, px);
15959 cpl_table_set_int(overscans, "ylow", nrows, py);
15960 cpl_table_set_int(overscans, "xhig", nrows, nx - ox);
15961 cpl_table_set_int(overscans, "yhig", nrows, ny - oy);
15962 nrows++;
15963
15964 cpl_table_set_int(overscans, "xlow", nrows, 0);
15965 cpl_table_set_int(overscans, "ylow", nrows, 0);
15966 cpl_table_set_int(overscans, "xhig", nrows, px);
15967 cpl_table_set_int(overscans, "yhig", nrows, ny);
15968 nrows++;
15969
15970 cpl_table_set_int(overscans, "xlow", nrows, nx - ox);
15971 cpl_table_set_int(overscans, "ylow", nrows, 0);
15972 cpl_table_set_int(overscans, "xhig", nrows, nx);
15973 cpl_table_set_int(overscans, "yhig", nrows, ny);
15974 nrows++;
15975 }
15976 else {
15977 overscans = mos_load_overscans_vimos(header, 0);
15978 }
15979
15980 return overscans;
15981
15982 }
15983
16015 #define READY 1
16016 #ifdef READY
16017
16018 cpl_polynomial *mos_montecarlo_polyfit(cpl_table *points, cpl_table *evaluate,
16019 int samples, int order)
16020 {
16021
16022 const char *func = "mos_montecarlo_polyfit";
16023
16024 cpl_polynomial *p;
16025 cpl_polynomial *q;
16026 cpl_vector *listx;
16027 cpl_vector *listy;
16028 double err;
16029 double *x;
16030 double *px;
16031 double *x_eval;
16032 double *px_eval;
16033 double *sigma;
16034 double *vy;
16035 double *dy;
16036 int npoints, nevaluate;
16037 int i, j;
16038
16039
16040 if (points == NULL || evaluate == NULL) {
16041 cpl_error_set(func, CPL_ERROR_NULL_INPUT);
16042 return NULL;
16043 }
16044
16045 if (!cpl_table_has_column(points, "x")) {
16046 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
16047 return NULL;
16048 }
16049
16050 if (cpl_table_get_column_type(points, "x") != CPL_TYPE_DOUBLE) {
16051 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
16052 return NULL;
16053 }
16054
16055 if (cpl_table_has_invalid(points, "x")) {
16056 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16057 return NULL;
16058 }
16059
16060 if (!cpl_table_has_column(points, "y")) {
16061 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
16062 return NULL;
16063 }
16064
16065 if (cpl_table_get_column_type(points, "y") != CPL_TYPE_DOUBLE) {
16066 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
16067 return NULL;
16068 }
16069
16070 if (cpl_table_has_invalid(points, "y")) {
16071 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16072 return NULL;
16073 }
16074
16075 if (cpl_table_has_column(points, "y_err")) {
16076
16077 if (cpl_table_get_column_type(points, "y_err") != CPL_TYPE_DOUBLE) {
16078 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
16079 return NULL;
16080 }
16081
16082 if (cpl_table_has_invalid(points, "y_err")) {
16083 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16084 return NULL;
16085 }
16086 }
16087
16088 if (!cpl_table_has_column(evaluate, "x")) {
16089 cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
16090 return NULL;
16091 }
16092
16093 if (cpl_table_get_column_type(evaluate, "x") != CPL_TYPE_DOUBLE) {
16094 cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
16095 return NULL;
16096 }
16097
16098 if (cpl_table_has_invalid(evaluate, "x")) {
16099 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16100 return NULL;
16101 }
16102
16103 if (samples < 2 || order < 0) {
16104 cpl_error_set(func, CPL_ERROR_ILLEGAL_INPUT);
16105 return NULL;
16106 }
16107
16108 npoints = cpl_table_get_nrow(points);
16109 listx = cpl_vector_wrap(npoints, cpl_table_get_data_double(points, "x"));
16110 listy = cpl_vector_wrap(npoints, cpl_table_get_data_double(points, "y"));
16111
16112 p = cpl_polynomial_fit_1d_create(listx, listy, order, &err);
16113
16114 if (!cpl_table_has_column(points, "y_err")) {
16115 err = sqrt(err);
16116 cpl_table_new_column(points, "y_err", CPL_TYPE_DOUBLE);
16117 cpl_table_fill_column_window_double(points, "y_err", 0, npoints, err);
16118 cpl_msg_info(func, "Error column not found - set to %f\n", err);
16119 }
16120
16121
16122
16123
16124
16125 if (cpl_table_has_column(points, "px"))
16126 cpl_table_erase_column(points, "px");
16127 cpl_table_new_column(points, "px", CPL_TYPE_DOUBLE);
16128 cpl_table_fill_column_window_double(points, "px", 0, npoints, 0);
16129 x = cpl_table_get_data_double(points, "x");
16130 px = cpl_table_get_data_double(points, "px");
16131 for (i = 0; i < npoints; i++)
16132 px[i] = cpl_polynomial_eval_1d(p, x[i], NULL);
16133
16134 nevaluate = cpl_table_get_nrow(evaluate);
16135
16136 if (cpl_table_has_column(evaluate, "px"))
16137 cpl_table_erase_column(evaluate, "px");
16138 cpl_table_new_column(evaluate, "px", CPL_TYPE_DOUBLE);
16139 cpl_table_fill_column_window_double(evaluate, "px", 0, nevaluate, 0);
16140 x_eval = cpl_table_get_data_double(evaluate, "x");
16141 px_eval = cpl_table_get_data_double(evaluate, "px");
16142 for (i = 0; i < nevaluate; i++)
16143 px_eval[i] = cpl_polynomial_eval_1d(p, x_eval[i], NULL);
16144
16145
16146
16147
16148
16149 if (cpl_table_has_column(evaluate, "sigma"))
16150 cpl_table_erase_column(evaluate, "sigma");
16151 cpl_table_new_column(evaluate, "sigma", CPL_TYPE_DOUBLE);
16152 cpl_table_fill_column_window_double(evaluate, "sigma", 0, nevaluate, 0);
16153 sigma = cpl_table_get_data_double(evaluate, "sigma");
16154
16155
16156
16157
16158
16159 if (cpl_table_has_column(points, "vy"))
16160 cpl_table_erase_column(points, "vy");
16161 cpl_table_new_column(points, "vy", CPL_TYPE_DOUBLE);
16162 cpl_table_fill_column_window_double(points, "vy", 0, npoints, 0);
16163 vy = cpl_table_get_data_double(points, "vy");
16164 dy = cpl_table_get_data_double(points, "y_err");
16165 cpl_vector_unwrap(listy);
16166 listy = cpl_vector_wrap(npoints, vy);
16167
16168 for (i = 0; i < samples; i++) {
16169 for (j = 0; j < npoints; j++)
16170 vy[j] = px[j] + dy[j] * mos_randg(1);
16171 q = cpl_polynomial_fit_1d_create(listx, listy, order, NULL);
16172 for (j = 0; j < nevaluate; j++)
16173 sigma[j] += fabs(px_eval[j]
16174 - cpl_polynomial_eval_1d(q, x_eval[j], NULL));
16175 cpl_polynomial_delete(q);
16176 }
16177
16178
16179
16180
16181
16182 cpl_table_multiply_scalar(evaluate, "sigma", 1.25);
16183 cpl_table_divide_scalar(evaluate, "sigma", samples);
16184
16185 cpl_vector_unwrap(listx);
16186 cpl_vector_unwrap(listy);
16187
16188 return p;
16189 }
16190
16191 #endif
16192
16215 cpl_error_code mos_randomise_image(cpl_image *image, double ron,
16216 double gain, double bias)
16217 {
16218 float *data;
16219 int npix, i;
16220
16221
16222 if (image == NULL)
16223 return cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
16224
16225 if (ron < 0.0 || gain <= FLT_EPSILON)
16226 return cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
16227
16228 data = cpl_image_get_data_float(image);
16229 npix = cpl_image_get_size_x(image) * cpl_image_get_size_y(image);
16230 ron *= ron;
16231
16232 for (i = 0; i < npix; i++) {
16233 if (data[i] < bias) {
16234 data[i] += sqrt(ron) * mos_randg(1);
16235 }
16236 else {
16237 data[i] += sqrt(ron + (data[i] - bias) / gain) * mos_randg(1);
16238 }
16239 }
16240
16241 return CPL_ERROR_NONE;
16242 }
16243
16244
16259 cpl_error_code mos_refmask_find_gaps(cpl_mask *refmask,
16260 cpl_image *master_flat,
16261 double level)
16262 {
16263 int nx = cpl_mask_get_size_x(refmask);
16264 int ny = cpl_mask_get_size_y(refmask);
16265
16266 int * xpos = cpl_calloc(sizeof(int), ny);
16267
16268 cpl_image * filtered = cpl_image_duplicate(master_flat);
16269 cpl_mask * kernel = cpl_mask_new(9, 3);
16270 cpl_vector * v = cpl_vector_new(ny);
16271 cpl_vector * truev;
16272 int nvalid = 0;
16273 double * flats = cpl_vector_get_data(v);
16274
16275 double median, stdev, delta;
16276
16277 int i, kill;
16278
16279 cpl_mask_not(kernel);
16280 cpl_image_filter_mask(filtered, master_flat, kernel,
16281 CPL_FILTER_MEDIAN, CPL_BORDER_COPY);
16282 cpl_mask_delete(kernel);
16283
16284 for (i = 1; i <= ny; i++) {
16285 int j = 0;
16286
16287 do j++;
16288 while (!cpl_mask_get(refmask, j, i) && j < nx);
16289
16290 if (j < nx) {
16291 int rejected;
16292
16293 xpos[i - 1] = j;
16294 flats[nvalid] = cpl_image_get(filtered, j, i, &rejected);
16295 nvalid++;
16296 }
16297 else {
16298 xpos[i - 1] = -1;
16299 }
16300 }
16301
16302 if (nvalid == 0)
16303 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
16304
16305 truev = cpl_vector_wrap(nvalid, flats);
16306
16307 median = cpl_vector_get_median(truev);
16308
16309 if (level < 0.0)
16310 stdev = cpl_vector_get_stdev(truev);
16311
16312 cpl_vector_unwrap(truev);
16313 cpl_vector_delete(v);
16314
16315 for (i = 1; i <= ny; i++) {
16316 if (xpos[i - 1] > 0) {
16317 int rejected;
16318 double kappa = 1.5;
16319
16320 delta = cpl_image_get(filtered, xpos[i - 1], i, &rejected) - median;
16321
16322 if (level < 0.0)
16323 kill = fabs(delta) > stdev * kappa;
16324 else
16325 kill = delta < level;
16326
16327 if (kill) {
16328 int j = 0;
16329
16330 while (cpl_mask_get(refmask, xpos[i - 1] + j, i)) {
16331 cpl_mask_set(refmask, xpos[i - 1] + j, i, CPL_BINARY_0);
16332 j++;
16333 }
16334 }
16335 }
16336 }
16337
16338 cpl_image_delete(filtered);
16339 cpl_free(xpos);
16340
16341 return cpl_error_get_code();
16342 }
16343
16351 cpl_error_code mos_saturation_process(cpl_image * image)
16352 {
16353 int nx = cpl_image_get_size_x(image);
16354 int ny = cpl_image_get_size_y(image);
16355 int npix = nx * ny;
16356 float * sdata = cpl_image_get_data_float(image);
16357
16358 int count, i, j, k;
16359
16360
16361
16362
16363
16364
16365
16366
16367
16368
16369
16370
16371
16372
16373
16374
16375
16376
16377
16378
16379
16380
16381
16382 for (i = 0; i < npix; i++) {
16383 if (sdata[i] >= 65535.0) {
16384 count = 0;
16385 for (j = i; j < npix; j++) {
16386 if (sdata[j] < 65535.0) {
16387 break;
16388 }
16389 else {
16390 count++;
16391 }
16392 }
16393 if (count < 30 && count > 2) {
16394 for (j = i; j < i + count/2; j++)
16395 sdata[j] = sdata[i] + 1000.0 * (j - i);
16396 if (count % 2 != 0) {
16397 sdata[j] = sdata[j-1] + 1000.0;
16398 j++;
16399 }
16400 for (k = j; k <= i + count; k++)
16401 sdata[k] = sdata[i] - 1000.0 * (k - i - count);
16402 i = k;
16403 }
16404 }
16405 }
16406
16407 return cpl_error_get_code();
16408 }
16409
16410
16419 cpl_error_code mos_subtract_background(cpl_image * image)
16420 {
16421
16422
16423
16424
16425 cpl_image * bimage = mos_arc_background(image, 15, 15);
16426 cpl_image_subtract(image, bimage);
16427 cpl_image_delete(bimage);
16428
16429 return cpl_error_get_code();
16430 }
16431
16432
16449 cpl_error_code mos_object_intersect(cpl_table **slitss, cpl_table *origslits,
16450 int nscience, float tolerance)
16451 {
16452 int i, j;
16453
16454 cpl_table *summary;
16455 int summary_nobjs = 0;
16456
16457 int nobjs;
16458
16459 int nmatches;
16460 int nslits = cpl_table_get_nrow(slitss[0]);
16461
16462 int maxobjs;
16463 int k, m;
16464 int nstokes, sstokes;
16465
16466 cpl_table **work;
16467
16468 work = (cpl_table **)cpl_malloc(sizeof(cpl_table *) * nscience);
16469
16470
16471
16472
16473
16474
16475
16476
16477
16478
16479 for (j = 0; j < nscience; j++) {
16480 int c_nobjs = mos_get_nobjects(slitss[j]);
16481 if (!c_nobjs)
16482 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
16483 summary_nobjs += c_nobjs;
16484 }
16485
16486 summary = cpl_table_new(summary_nobjs);
16487
16488 cpl_table_new_column(summary, "offset", CPL_TYPE_DOUBLE);
16489 cpl_table_new_column(summary, "pair", CPL_TYPE_INT);
16490 cpl_table_new_column(summary, "absolute", CPL_TYPE_DOUBLE);
16491 cpl_table_new_column(summary, "pos", CPL_TYPE_DOUBLE);
16492
16493
16494
16495
16496
16497 nobjs = 0;
16498
16499
16500 for (j = 0; j < nscience; j++) {
16501 int c_maxobjs = mos_get_maxobjs_per_slit(slitss[j]);
16502
16503
16504 for (k = 0; k < nslits; k++) {
16505
16506
16507 for (m = 0; m < c_maxobjs; m++) {
16508 int null;
16509 char *name = cpl_sprintf("object_%d", m + 1);
16510 double obj = cpl_table_get_double(slitss[j], name, k, &null);
16511 int pos;
16512 int pair;
16513
16514 cpl_free(name);
16515
16516 if (null)
16517 break;
16518
16519
16520
16521
16522
16523
16524
16525
16526 pos = cpl_table_get_int(slitss[j], "position", k, &null);
16527 pair = cpl_table_get_int(slitss[j], "pair_id", k, &null);
16528 cpl_table_set(summary, "absolute", nobjs, obj);
16529 cpl_table_set(summary, "pos", nobjs, pos);
16530 cpl_table_set(summary, "offset", nobjs, obj - pos);
16531 cpl_table_set(summary, "pair", nobjs, pair);
16532
16533 nobjs++;
16534 }
16535 }
16536 }
16537
16538
16539
16540
16541
16542
16543
16544
16545
16546
16547 nmatches = 0;
16548 maxobjs = mos_get_maxobjs_per_slit(slitss[0]);
16549
16550
16551
16552
16553
16554
16555
16556
16557
16558
16559
16560
16561 for (k = 0; k < nslits; k+=2) {
16562 int slitmatches = 0;
16563
16564 if (k + 1 < nslits ) {
16565 if (cpl_table_get_int(slitss[0], "pair_id", k, NULL) !=
16566 cpl_table_get_int(slitss[0], "pair_id", k + 1, NULL)) {
16567
16568
16569
16570
16571
16572
16573 k--;
16574
16575 continue;
16576 }
16577 }
16578
16579 for (m = 0; m < maxobjs; m++) {
16580 int null;
16581 char *name = cpl_sprintf("object_%d", m + 1);
16582 double obj = cpl_table_get_double(slitss[0], name, k, &null);
16583 double pos;
16584 int pair;
16585
16586 char *name_obj = NULL;
16587 char *name_start = NULL;
16588 char *name_end = NULL;
16589 char *name_row = NULL;
16590 char *name_row_s = NULL;
16591
16592 char *name_start_o = NULL;
16593 char *name_end_o = NULL;
16594 char *name_row_o = NULL;
16595 char *name_start_v = NULL;
16596 char *name_end_v = NULL;
16597 char *name_obj_v = NULL;
16598
16599 int start, end;
16600 int length;
16601
16602 int selected;
16603 int v, start_v, end_v;
16604 double min_v, obj_v;
16605
16606
16607 cpl_free(name);
16608
16609 if (null)
16610 break;
16611
16612
16613
16614
16615
16616
16617
16618
16619 pos = cpl_table_get_int(slitss[0], "position", k, &null);
16620 pair = cpl_table_get_int(slitss[0], "pair_id", k, &null);
16621
16622
16623
16624
16625
16626
16627
16628
16629 cpl_table_select_all(summary);
16630
16631 cpl_table_and_selected_int(summary, "pair", CPL_EQUAL_TO, pair);
16632 cpl_table_and_selected_double(summary, "offset", CPL_LESS_THAN,
16633 obj - pos + tolerance);
16634 selected =
16635 cpl_table_and_selected_double(summary, "offset", CPL_GREATER_THAN,
16636 obj - pos - tolerance);
16637
16638
16639
16640
16641
16642
16643
16644
16645
16646 if (selected != nscience * 2)
16647 continue;
16648
16649
16650
16651
16652
16653
16654
16655 slitmatches++;
16656
16657
16658
16659
16660
16661
16662
16663
16664
16665
16666
16667 name_obj = cpl_sprintf("object_%d", slitmatches);
16668 name_start = cpl_sprintf("start_%d", slitmatches);
16669 name_end = cpl_sprintf("end_%d", slitmatches);
16670 name_row = cpl_sprintf("row_%d", slitmatches);
16671 name_row_s = cpl_sprintf("row_stokes_%d", slitmatches);
16672
16673
16674
16675
16676
16677
16678 name_start_o = cpl_sprintf("start_%d", m + 1);
16679 name_end_o = cpl_sprintf("end_%d", m + 1);
16680 name_row_o = cpl_sprintf("row_%d", m + 1);
16681
16682
16683
16684
16685
16686 if (!cpl_table_has_column(origslits, name_obj)) {
16687 cpl_table_new_column(origslits, name_obj, CPL_TYPE_DOUBLE);
16688 cpl_table_new_column(origslits, name_start, CPL_TYPE_INT);
16689 cpl_table_new_column(origslits, name_end, CPL_TYPE_INT);
16690 cpl_table_new_column(origslits, name_row, CPL_TYPE_INT);
16691 cpl_table_new_column(origslits, name_row_s, CPL_TYPE_INT);
16692 }
16693
16694
16695
16696
16697
16698
16699
16700
16701 length = cpl_table_get_int(origslits, "length", k + 1, &null);
16702
16703
16704
16705
16706
16707
16708
16709 for (v = 0; v < maxobjs; v++) {
16710 char *name_v = cpl_sprintf("object_%d", v + 1);
16711 double obj_v = cpl_table_get_double(slitss[0], name_v,
16712 k + 1, &null);
16713
16714 cpl_free(name_v);
16715
16716 if (null)
16717 break;
16718
16719 if (v) {
16720 if (fabs(obj - length - obj_v) < min_v) {
16721 min_v = fabs(obj - length - obj_v);
16722 cpl_free(name_start_v);
16723 cpl_free(name_end_v);
16724 cpl_free(name_obj_v);
16725 name_start_v = cpl_sprintf("start_%d", v + 1);
16726 name_end_v = cpl_sprintf("end_%d", v + 1);
16727 name_obj_v = cpl_sprintf("object_%d", v + 1);
16728 }
16729 }
16730 else {
16731 min_v = fabs(obj - length - obj_v);
16732 name_start_v = cpl_sprintf("start_%d", v + 1);
16733 name_end_v = cpl_sprintf("end_%d", v + 1);
16734 name_obj_v = cpl_sprintf("object_%d", v + 1);
16735 }
16736 }
16737
16738
16739
16740
16741
16742
16743 start = cpl_table_get_int(slitss[0], name_start_o, k, &null);
16744 end = cpl_table_get_int(slitss[0], name_end_o, k, &null);
16745
16746
16747
16748
16749
16750 start_v = cpl_table_get_int(slitss[0], name_start_v, k + 1, &null);
16751 end_v = cpl_table_get_int(slitss[0], name_end_v, k + 1, &null);
16752 obj_v = cpl_table_get_double(slitss[0], name_obj_v, k + 1, &null);
16753
16754
16755
16756
16757
16758
16759
16760
16761
16762
16763 cpl_table_set_double(origslits, name_obj, k, obj);
16764 cpl_table_set_double(origslits, name_obj, k + 1, obj_v);
16765
16766
16767 cpl_table_set_int(origslits, name_start, k, start);
16768 cpl_table_set_int(origslits, name_start, k + 1, start_v);
16769
16770
16771 cpl_table_set_int(origslits, name_end, k, end);
16772 cpl_table_set_int(origslits, name_end, k + 1, end_v);
16773
16774
16775
16776
16777
16778
16779
16780
16781
16782
16783
16784
16785
16786
16787 cpl_table_set_int(origslits, name_row, k, nmatches);
16788 nmatches++;
16789 cpl_table_set_int(origslits, name_row, k + 1, nmatches);
16790 nmatches++;
16791
16792 cpl_free(name_obj);
16793 cpl_free(name_start);
16794 cpl_free(name_end);
16795 cpl_free(name_row);
16796 cpl_free(name_row_s);
16797
16798 cpl_free(name_start_o);
16799 cpl_free(name_end_o);
16800 cpl_free(name_row_o);
16801
16802 cpl_free(name_start_v); name_start_v = NULL;
16803 cpl_free(name_end_v); name_end_v = NULL;
16804 cpl_free(name_obj_v); name_obj_v = NULL;
16805 }
16806 }
16807
16808
16809
16810
16811
16812
16813 cpl_table_delete(summary);
16814
16815 if (!nmatches)
16816 return cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
16817
16818
16819
16820
16821
16822
16823
16824
16825
16826
16827
16828 maxobjs = mos_get_maxobjs_per_slit(origslits);
16829 nstokes = nmatches / 2;
16830
16831 for (k = 0; k < nslits; k++) {
16832 if (k % 2) {
16833 nstokes = sstokes;
16834 }
16835 else {
16836 sstokes = nstokes;
16837 }
16838
16839 for (m = 0; m < maxobjs; m++) {
16840 char *name = cpl_sprintf("row_%d", m + 1);
16841 char *namestokes = cpl_sprintf("row_stokes_%d", m + 1);
16842
16843 if (!cpl_table_is_valid(origslits, name, k)) {
16844 cpl_free(name);
16845 cpl_free(namestokes);
16846 break;
16847 }
16848 else {
16849 nmatches--;
16850 nstokes--;
16851 cpl_table_set_int(origslits, name, k, nmatches);
16852 cpl_table_set_int(origslits, namestokes, k, nstokes);
16853 }
16854
16855 cpl_free(name);
16856 cpl_free(namestokes);
16857 }
16858 }
16859
16860
16861
16862
16863
16864
16865
16866
16867
16868 for (j = 0; j < maxobjs; j++) {
16869 char *name = cpl_sprintf("object_%d", j + 1);
16870 cpl_table_fill_invalid_double(origslits, name, -1);
16871 cpl_free(name);
16872
16873 name = cpl_sprintf("start_%d", j + 1);
16874 cpl_table_fill_invalid_int(origslits, name, -1);
16875 cpl_free(name);
16876
16877 name = cpl_sprintf("end_%d", j + 1);
16878 cpl_table_fill_invalid_int(origslits, name, -1);
16879 cpl_free(name);
16880
16881 name = cpl_sprintf("row_%d", j + 1);
16882 cpl_table_fill_invalid_int(origslits, name, -1);
16883 cpl_free(name);
16884
16885 name = cpl_sprintf("row_stokes_%d", j + 1);
16886 cpl_table_fill_invalid_int(origslits, name, -1);
16887 cpl_free(name);
16888 }
16889
16890
16891
16892
16893
16894
16895
16896
16897
16898
16899
16900
16901 for (i = 0; i < nscience; i++) {
16902 int c_maxobjs = mos_get_maxobjs_per_slit(slitss[i]);
16903
16904 work[i] = cpl_table_duplicate(slitss[i]);
16905
16906 for (m = 0; m < c_maxobjs; m++) {
16907 char *object_o = cpl_sprintf("object_%d", m + 1);
16908 char *start_o = cpl_sprintf("start_%d", m + 1);
16909 char *end_o = cpl_sprintf("end_%d", m + 1);
16910 char *row_o = cpl_sprintf("row_%d", m + 1);
16911
16912 cpl_table_erase_column(slitss[i], object_o);
16913 cpl_table_erase_column(slitss[i], start_o);
16914 cpl_table_erase_column(slitss[i], end_o);
16915 cpl_table_erase_column(slitss[i], row_o);
16916 }
16917 }
16918
16919
16920
16921
16922
16923 for (k = 0; k < nslits; k++) {
16924 for (j = 0; j < maxobjs; j++) {
16925 double object_w, object_r;
16926 int row_w;
16927
16928 char *object_i = cpl_sprintf("object_%d", j + 1);
16929 char *start_i = cpl_sprintf("start_%d", j + 1);
16930 char *end_i = cpl_sprintf("end_%d", j + 1);
16931 char *row_i = cpl_sprintf("row_%d", j + 1);
16932
16933
16934 if (!cpl_table_is_valid(origslits, object_i, k))
16935 break;
16936
16937
16938
16939
16940
16941
16942
16943
16944
16945
16946
16947 object_w = cpl_table_get_double(origslits, object_i, k, NULL);
16948 row_w = cpl_table_get_int (origslits, row_i, k, NULL);
16949
16950 for (i = 0; i < nscience; i++) {
16951 int c_maxobjs = mos_get_maxobjs_per_slit(work[i]);
16952 int minpos;
16953 double mindiff, diff;
16954 char *object_o;
16955 char *start_o;
16956 char *end_o;
16957 char *row_o;
16958
16959 for (m = 0; m < c_maxobjs; m++) {
16960 object_o = cpl_sprintf("object_%d", m + 1);
16961 start_o = cpl_sprintf("start_%d", m + 1);
16962 end_o = cpl_sprintf("end_%d", m + 1);
16963 row_o = cpl_sprintf("row_%d", m + 1);
16964
16965 if (!cpl_table_is_valid(work[i], object_o, k))
16966 break;
16967
16968 object_r = cpl_table_get_double(work[i], object_o, k, NULL);
16969
16970
16971 diff = fabs(object_w - object_r);
16972 if (m) {
16973 if (mindiff > diff) {
16974 mindiff = diff;
16975 minpos = m;
16976 }
16977 }
16978 else {
16979 mindiff = diff;
16980 minpos = 0;
16981 }
16982
16983 cpl_free(object_o);
16984 cpl_free(start_o);
16985 cpl_free(end_o);
16986 cpl_free(row_o);
16987 }
16988
16989 object_o = cpl_sprintf("object_%d", minpos + 1);
16990 start_o = cpl_sprintf("start_%d", minpos + 1);
16991 end_o = cpl_sprintf("end_%d", minpos + 1);
16992 row_o = cpl_sprintf("row_%d", minpos + 1);
16993
16994 if (!cpl_table_has_column(slitss[i], object_i)) {
16995 cpl_table_new_column(slitss[i], object_i, CPL_TYPE_DOUBLE);
16996 cpl_table_new_column(slitss[i], start_i, CPL_TYPE_INT);
16997 cpl_table_new_column(slitss[i], end_i, CPL_TYPE_INT);
16998 cpl_table_new_column(slitss[i], row_i, CPL_TYPE_INT);
16999 cpl_table_fill_invalid_double(slitss[i], object_i, -1);
17000 cpl_table_fill_invalid_int (slitss[i], start_i, -1);
17001 cpl_table_fill_invalid_int (slitss[i], end_i, -1);
17002 cpl_table_fill_invalid_int (slitss[i], row_i, -1);
17003 }
17004
17005 cpl_table_set_double(slitss[i], object_i, k,
17006 cpl_table_get_double(work[i], object_o,
17007 k, NULL));
17008 cpl_table_set_int(slitss[i], start_i , k,
17009 cpl_table_get_int(work[i], start_o, k, NULL));
17010 cpl_table_set_int(slitss[i], end_i , k,
17011 cpl_table_get_int(work[i], end_o, k, NULL));
17012 cpl_table_set_int(slitss[i], row_i , k, row_w);
17013
17014 cpl_free(object_o);
17015 cpl_free(start_o);
17016 cpl_free(end_o);
17017 cpl_free(row_o);
17018 }
17019
17020 cpl_free(object_i);
17021 cpl_free(start_i);
17022 cpl_free(end_i);
17023 cpl_free(row_i);
17024 }
17025 }
17026
17027 for (i = 0; i < nscience; i++)
17028 cpl_table_delete(work[i]);
17029
17030 cpl_free(work);
17031
17032
17033 return cpl_error_get_code();
17034 }
17035
17036
17044 int mos_get_maxobjs_per_slit(cpl_table * slits)
17045 {
17046 int maxobjs = 1;
17047
17048 char * colname = cpl_sprintf("object_%d", maxobjs);
17049
17050 while (cpl_table_has_column(slits, colname)) {
17051 maxobjs++;
17052 cpl_free(colname);
17053 colname = cpl_sprintf("object_%d", maxobjs);
17054 }
17055
17056 cpl_free(colname);
17057
17058 maxobjs--;
17059
17060 return maxobjs;
17061 }
17062
17070 int mos_get_nobjects(cpl_table * slits)
17071 {
17072 int nobjs = 0;
17073
17074 int nslits = cpl_table_get_nrow(slits);
17075 int maxobjs = mos_get_maxobjs_per_slit(slits);
17076
17077 int k, m;
17078
17079 for (k = 0; k < nslits; k++) {
17080 for (m = 0; m < maxobjs; m++) {
17081 char * name = cpl_sprintf("object_%d", m + 1);
17082 int null = !cpl_table_is_valid(slits, name, k);
17083
17084 cpl_free(name);
17085
17086 if (null) break;
17087 else nobjs++;
17088 }
17089 }
17090
17091 return nobjs;
17092 }
17093
17101 int mos_check_slits(cpl_table *slits, float rescale)
17102 {
17103
17104 cpl_propertylist *sort;
17105
17106 int nslits = cpl_table_get_nrow(slits);
17107
17108 int k, null;
17109
17110 const float interval = 90.0 * rescale;
17111 const float offset = (90.0 - 5) * rescale;
17112
17113
17114 for (k = 0; k < nslits; k++) {
17115 double ytop = cpl_table_get_double(slits, "ytop", k, &null);
17116 double ybottom = cpl_table_get_double(slits, "ybottom", k, &null);
17117
17118 double xtop = cpl_table_get_double(slits, "xtop", k, &null);
17119 double xbottom = cpl_table_get_double(slits, "xbottom", k, &null);
17120
17121 int nmiss = (int)((ytop - ybottom) / interval + 0.5);
17122
17123 if (nmiss > 1) {
17124 cpl_msg_warning(cpl_func,
17125 "Some slits could not be properly detected. "
17126 "There might be accountable inaccuracies.");
17127 while (nmiss > 1) {
17128 cpl_table_set_size(slits, nslits + 1);
17129
17130
17131
17132
17133 cpl_table_set_double(slits, "xtop", nslits, xtop);
17134 cpl_table_set_double(slits, "xbottom", nslits, xbottom);
17135
17136
17137 if (k == 0) {
17138 cpl_table_set_double(slits, "ybottom", nslits, ybottom);
17139 cpl_table_set_double(slits, "ytop", nslits, ybottom
17140 + offset);
17141 ybottom += interval;
17142 cpl_table_set_double(slits, "ybottom", k, ybottom);
17143 } else {
17144 cpl_table_set_double(slits, "ytop", nslits, ytop);
17145 cpl_table_set_double(slits, "ybottom", nslits, ytop
17146 - offset);
17147 ytop -= interval;
17148 cpl_table_set_double(slits, "ytop", k, ytop);
17149 }
17150
17151 nslits++; nmiss--;
17152 }
17153 }
17154 }
17155
17156 sort = cpl_propertylist_new();
17157 cpl_propertylist_append_bool(sort, "ytop", 1);
17158 cpl_table_sort(slits, sort);
17159 cpl_propertylist_delete(sort);
17160
17161
17162
17163
17164
17165
17166 k = cpl_table_get_nrow(slits) - 1;
17167
17168 {
17169 double ytop = cpl_table_get_double(slits, "ytop", k, &null);
17170 double ybottom = cpl_table_get_double(slits, "ybottom", k, &null);
17171 double length = (ytop - ybottom) / interval;
17172
17173 if (length > 1.1) {
17174 cpl_table_set_double(slits, "ybottom", k, ytop - offset);
17175 }
17176
17177 }
17178
17179 return 0;
17180 }
17181
17204 cpl_table *mos_load_slits_fors_pmos(cpl_propertylist *header,
17205 int * nslits_out_det)
17206 {
17207 int m, null;
17208 int halfsize;
17209
17210 cpl_propertylist * sort;
17211 cpl_table * slits;
17212
17213 slits = mos_load_slits_fors_mos(header, nslits_out_det);
17214 halfsize = cpl_table_get_nrow(slits);
17215
17216 cpl_table_set_size(slits, 2 * halfsize);
17217
17218 for (m = 0; m < halfsize; m++) {
17219
17220 double gap = 1.4;
17221
17222 double length =
17223 cpl_table_get(slits, "ytop", m, &null) -
17224 cpl_table_get(slits, "ybottom", m, &null);
17225
17226 if (m) {
17227 double interval =
17228 cpl_table_get(slits, "ybottom", m - 1, &null) -
17229 cpl_table_get(slits, "ytop", m, &null);
17230
17231 gap = (interval - length) / 2;
17232 }
17233
17234 cpl_table_set(slits, "slit_id", m + halfsize,
17235 cpl_table_get(slits, "slit_id", m, &null) - 1);
17236
17237 cpl_table_set(slits, "xtop", m + halfsize,
17238 cpl_table_get(slits, "xtop", m, &null));
17239
17240 cpl_table_set(slits, "xbottom", m + halfsize,
17241 cpl_table_get(slits, "xbottom", m, &null));
17242
17243 cpl_table_set(slits, "ytop", m + halfsize,
17244 cpl_table_get(slits, "ytop", m, &null) + gap + length);
17245
17246 cpl_table_set(slits, "ybottom", m + halfsize,
17247 cpl_table_get(slits, "ytop", m, &null) + gap);
17248 }
17249
17250 for (m = 0; m < 2 * halfsize; m++) {
17251 cpl_table_set(slits, "ytop", m,
17252 cpl_table_get(slits, "ytop", m, &null) - 5.3);
17253
17254 cpl_table_set(slits, "ybottom", m,
17255 cpl_table_get(slits, "ybottom", m, &null) - 5.3);
17256
17257 }
17258
17259 sort = cpl_propertylist_new();
17260 cpl_propertylist_append_bool(sort, "ytop", 1);
17261 cpl_table_sort(slits, sort);
17262
17263 cpl_propertylist_delete(sort);
17264
17265 return slits;
17266 }
17267
17268 int * fors_get_nobjs_perslit(cpl_table * slits)
17269 {
17270 int nslits = cpl_table_get_nrow(slits);
17271 int maxobjs = mos_get_maxobjs_per_slit(slits);
17272
17273 int * nobjs_per_slit = cpl_malloc(sizeof(int) * nslits);
17274
17275 int k, m;
17276
17277 for (k = 0; k < nslits; k++) {
17278 int nobjs = 0;
17279 for (m = 0; m < maxobjs; m++) {
17280 char * name = cpl_sprintf("object_%d", m + 1);
17281 int null = !cpl_table_is_valid(slits, name, k);
17282
17283 cpl_free(name);
17284
17285 if (null) break;
17286 else nobjs++;
17287 }
17288
17289 nobjs_per_slit[k] = nobjs;
17290 }
17291
17292 return nobjs_per_slit;
17293 }
17294
17295 double fors_get_object_position(cpl_table *slits, int slit, int object)
17296 {
17297 char *name = cpl_sprintf("object_%d", object);
17298 double position;
17299
17300 position = cpl_table_get_double(slits, name, slit, NULL)
17301 - cpl_table_get_int(slits, "position", slit, NULL);
17302
17303 cpl_free(name);
17304
17305 return position;
17306 }
17307
17308 int mos_rebin_signal(cpl_image **image, int rebin)
17309 {
17310 cpl_image *rebinned;
17311
17312
17313 if (*image == NULL)
17314 return 1;
17315
17316 if (rebin == 1)
17317 return 0;
17318
17319 rebinned = cpl_image_rebin(*image, 1, 1, rebin, 1);
17320
17321 cpl_image_delete(*image);
17322
17323 *image = rebinned;
17324
17325 return 0;
17326 }
17327
17328 int mos_rebin_error(cpl_image **image, int rebin)
17329 {
17330 if (*image == NULL)
17331 return 1;
17332
17333 if (rebin == 1)
17334 return 0;
17335
17336 cpl_image_power(*image, 2);
17337 mos_rebin_signal(image, rebin);
17338 cpl_image_power(*image, 0.5);
17339
17340 return 0;
17341 }
17342
17343
17344
17345
17346
17347
17348
17349
17350
17351
17352
17353
17354
17355
17356
17357
17358
17359
17360 int map_table(cpl_image *image, double start, double step,
17361 cpl_table *table, const char *xname, const char *yname)
17362 {
17363 int length = cpl_image_get_size_x(image);
17364 int nrows = cpl_table_get_nrow(table);
17365 float *data = cpl_image_get_data_float(image);
17366 float *fdata = NULL;
17367 double *xdata = NULL;
17368 double *ydata = NULL;
17369 cpl_type xtype = cpl_table_get_column_type(table, xname);
17370 cpl_type ytype = cpl_table_get_column_type(table, yname);
17371 double xzero, pos;
17372 int i, j, n;
17373
17374
17375
17376
17377
17378
17379
17380 for (i = 0; i < length; i++)
17381 data[i] = 0.0;
17382
17383
17384
17385
17386
17387
17388 if (xtype == CPL_TYPE_FLOAT) {
17389 fdata = cpl_table_get_data_float(table, xname);
17390 xdata = cpl_malloc(nrows * sizeof(double));
17391 for (i = 0; i < nrows; i++) {
17392 xdata[i] = fdata[i];
17393 }
17394 }
17395 else {
17396 xdata = cpl_table_get_data_double(table, xname);
17397 }
17398
17399 if (ytype == CPL_TYPE_FLOAT) {
17400 fdata = cpl_table_get_data_float(table, yname);
17401 ydata = cpl_malloc(nrows * sizeof(double));
17402 for (i = 0; i < nrows; i++) {
17403 ydata[i] = fdata[i];
17404 }
17405 }
17406 else {
17407 ydata = cpl_table_get_data_double(table, yname);
17408 }
17409
17410
17411
17412
17413
17414 n = 0;
17415 xzero = xdata[n];
17416
17417 for (i = 0; i < length; i++) {
17418 pos = start + step * i;
17419 if (pos < xzero)
17420 continue;
17421 for (j = n; j < nrows; j++) {
17422 if (xdata[j] > pos) {
17423 n = j;
17424 data[i] = ydata[j-1]
17425 + (ydata[j] - ydata[j-1])
17426 * (pos - xdata[j-1]) / (xdata[j] - xdata[j-1]);
17427 break;
17428 }
17429 }
17430 }
17431
17432 if (xtype == CPL_TYPE_FLOAT)
17433 cpl_free(xdata);
17434
17435 if (ytype == CPL_TYPE_FLOAT)
17436 cpl_free(ydata);
17437
17438 return 0;
17439 }
17440
17441
17442
17443
17444
17445
17446
17447
17448
17449
17450
17451
17452
17453
17454
17455 static cpl_image *polysmooth(cpl_image *image, int order, int hw)
17456 {
17457 int npoints;
17458 cpl_vector *x;
17459 cpl_vector *y;
17460 double *xdata;
17461 double *ydata;
17462 cpl_polynomial *poly;
17463 cpl_vector *ysmooth;
17464 cpl_image *smoothed;
17465 float *sdata;
17466 int i;
17467
17468
17469 npoints = cpl_image_get_size_x(image);
17470
17471 if (2 * hw + 1 > npoints)
17472 return NULL;
17473
17474 x = cpl_vector_new(npoints);
17475 y = cpl_vector_new(npoints);
17476 xdata = cpl_vector_get_data(x);
17477 ydata = cpl_vector_get_data(y);
17478
17479 smoothed = cpl_image_duplicate(image);
17480 sdata = cpl_image_get_data_float(smoothed);
17481
17482 for (i = 0; i < npoints; i++) {
17483 xdata[i] = i;
17484 ydata[i] = sdata[i];
17485 }
17486
17487 ysmooth = cpl_vector_filter_median_create(y, hw);
17488 cpl_vector_delete(y);
17489
17490 poly = cpl_polynomial_fit_1d_create(x, ysmooth, order, NULL);
17491 cpl_vector_delete(x);
17492 cpl_vector_delete(ysmooth);
17493
17494 if (poly) {
17495 for (i = 0; i < npoints; i++)
17496 sdata[i] = cpl_polynomial_eval_1d(poly, i, NULL);
17497
17498 cpl_polynomial_delete(poly);
17499 }
17500 else {
17501 cpl_image_delete(smoothed);
17502 return NULL;
17503 }
17504
17505 return smoothed;
17506 }
17507
17508 #undef cleanup
17509 #define cleanup \
17510 do { \
17511 cpl_image_delete(spectrum); \
17512 cpl_image_delete(flux); \
17513 cpl_image_delete(efficiency); \
17514 cpl_image_delete(smo_efficiency); \
17515 cpl_image_delete(extinction); \
17516 cpl_image_delete(response); \
17517 cpl_image_delete(smo_response); \
17518 cpl_image_delete(physical); \
17519 } while (0)
17520
17544 cpl_table *mos_photometric_calibration(cpl_image *spectra, double startwave,
17545 double dispersion, double gain,
17546 double exptime, cpl_table *ext_table,
17547 double airmass, cpl_table *flux_table,
17548 int order)
17549 {
17550
17551 cpl_image *spectrum = NULL;
17552 float *data;
17553 cpl_image *extinction = NULL;
17554 float *ext_data;
17555 cpl_image *flux = NULL;
17556 float *flux_data;
17557 cpl_image *physical = NULL;
17558 float *phys_data;
17559 cpl_image *efficiency = NULL;
17560 float *eff_data;
17561 cpl_image *smo_efficiency = NULL;
17562 float *smo_eff_data;
17563 cpl_image *response = NULL;
17564 float *res_data;
17565 cpl_image *smo_response = NULL;
17566 float *smo_res_data;
17567 cpl_image *image;
17568 cpl_image *smo_image;
17569 cpl_table *table;
17570 float lambda;
17571 int nx, ny;
17572 int ext_count, ext_pos;
17573 int eff_count, eff_pos;
17574 int flux_count, flux_pos;
17575 int start, end;
17576 int i;
17577
17578
17579 if (spectra == NULL || ext_table == NULL || flux_table == NULL) {
17580 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
17581 return NULL;
17582 }
17583
17584 if (!cpl_table_has_column(ext_table, "WAVE")) {
17585 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17586 "Column WAVE in atmospheric extinction table");
17587 return NULL;
17588 }
17589
17590 if (!cpl_table_has_column(ext_table, "EXTINCTION")) {
17591 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17592 "Column EXTINCTION in atmospheric extinction table");
17593 return NULL;
17594 }
17595
17596 if (!cpl_table_has_column(flux_table, "WAVE")) {
17597 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17598 "Column WAVE in standard star flux table");
17599 return NULL;
17600 }
17601
17602 if (!cpl_table_has_column(flux_table, "FLUX")) {
17603 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
17604 "Column FLUX in standard star flux table");
17605 return NULL;
17606 }
17607
17608 if (gain < 0.1) {
17609 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17610 "Invalid gain factor (%.2f)", gain);
17611 return NULL;
17612 }
17613
17614 if (exptime < 0.001) {
17615 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17616 "Invalid exposure time (%.2f)", exptime);
17617 return NULL;
17618 }
17619
17620 if (dispersion < 0.001) {
17621 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17622 "Invalid dispersion (%.2f)", dispersion);
17623 return NULL;
17624 }
17625
17626 if (order < 2) {
17627 cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
17628 "Order of the polynomial fitting the "
17629 "instrument response must be at least 2");
17630 return NULL;
17631 }
17632
17633 nx = cpl_image_get_size_x(spectra);
17634 ny = cpl_image_get_size_y(spectra);
17635
17636
17637
17638
17639
17640
17641 if (ny == 1) {
17642 spectrum = cpl_image_duplicate(spectra);
17643 }
17644 else {
17645 cpl_size x, y;
17646 cpl_image *brights = cpl_image_collapse_create(spectra, 1);
17647
17648 cpl_image_get_maxpos(brights, &x, &y);
17649 cpl_image_delete(brights);
17650 spectrum = cpl_image_extract(spectra, 1, y, nx, y);
17651 }
17652
17653
17654
17655
17656
17657
17658 cpl_image_multiply_scalar(spectrum, gain / exptime / dispersion);
17659
17660
17661
17662
17663
17664
17665
17666 extinction = cpl_image_duplicate(spectrum);
17667 map_table(extinction, startwave + dispersion/2, dispersion,
17668 ext_table, "WAVE", "EXTINCTION");
17669
17670
17671
17672
17673
17674
17675 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
17676 cpl_image_exponential(extinction, 10.);
17677
17678
17679
17680
17681
17682
17683 cpl_image_multiply(spectrum, extinction);
17684
17685
17686
17687
17688
17689
17690
17691 ext_data = cpl_image_get_data_float(extinction);
17692
17693 ext_count = 0;
17694 ext_pos = 0;
17695 for (i = 0; i < nx; i++) {
17696 if (ext_data[i] > 0.0) {
17697 if (ext_count == 0) {
17698 ext_pos = i;
17699 }
17700 ext_count++;
17701 }
17702 else {
17703 if (ext_count) {
17704 break;
17705 }
17706 }
17707 }
17708
17709 cpl_image_delete(extinction); extinction = NULL;
17710
17711
17712
17713
17714
17715
17716
17717 flux = cpl_image_duplicate(spectrum);
17718 map_table(flux, startwave + dispersion/2, dispersion,
17719 flux_table, "WAVE", "FLUX");
17720
17721
17722
17723
17724
17725
17726
17727 flux_data = cpl_image_get_data_float(flux);
17728
17729 flux_count = 0;
17730 flux_pos = 0;
17731 for (i = 0; i < nx; i++) {
17732 if (flux_data[i] > 0.0) {
17733 if (flux_count == 0) {
17734 flux_pos = i;
17735 }
17736 flux_count++;
17737 }
17738 else {
17739 if (flux_count) {
17740 break;
17741 }
17742 }
17743 }
17744
17745
17746
17747
17748
17749
17750 start = ext_pos > flux_pos ? ext_pos : flux_pos;
17751 end = (ext_pos + ext_count) < (flux_pos + flux_count) ?
17752 (ext_pos + ext_count) : (flux_pos + flux_count);
17753 flux_pos = start;
17754 flux_count = end - start;
17755
17756
17757
17758
17759
17760
17761
17762
17763
17764
17765 physical = cpl_image_duplicate(spectrum);
17766 phys_data = cpl_image_get_data_float(physical);
17767
17768 for (i = 0; i < nx; i++) {
17769 lambda = startwave + dispersion * (i + 0.5);
17770 phys_data[i] = 0.0026 * lambda * flux_data[i];
17771 }
17772
17773 efficiency = cpl_image_duplicate(spectrum);
17774 eff_data = cpl_image_get_data_float(efficiency);
17775 data = cpl_image_get_data_float(spectrum);
17776
17777 for (i = 0; i < nx; i++) {
17778 if (phys_data[i] > 0.0)
17779 eff_data[i] = data[i] / phys_data[i];
17780 else
17781 eff_data[i] = 0.0;
17782 }
17783
17784 cpl_image_delete(physical); physical = NULL;
17785
17786
17787
17788
17789
17790
17791
17792 eff_count = 0;
17793 eff_pos = 0;
17794 for (i = 0; i < nx; i++) {
17795 if (eff_data[i] > 0.01) {
17796 if (eff_count == 0) {
17797 eff_pos = i;
17798 }
17799 eff_count++;
17800 }
17801 else {
17802 if (eff_count > 300) {
17803 break;
17804 }
17805 }
17806 }
17807
17808
17809
17810
17811
17812
17813 start = eff_pos > flux_pos ? eff_pos : flux_pos;
17814 end = (eff_pos + eff_count) < (flux_pos + flux_count) ?
17815 (eff_pos + eff_count) : (flux_pos + flux_count);
17816 eff_pos = start;
17817 eff_count = end - start;
17818
17819 if (eff_count < 1) {
17820 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
17821 "No overlap between catalog and spectrum");
17822 cleanup;
17823 return NULL;
17824 }
17825
17826
17827
17828
17829
17830
17831 image = cpl_image_extract(efficiency, eff_pos + 1, 1,
17832 eff_pos + eff_count, 1);
17833
17834 smo_image = polysmooth(image, order, 50);
17835 cpl_image_delete(image);
17836
17837 smo_efficiency = cpl_image_duplicate(efficiency);
17838 smo_eff_data = cpl_image_get_data_float(smo_efficiency);
17839 cpl_image_copy(smo_efficiency, smo_image, eff_pos + 1, 1);
17840
17841 cpl_image_delete(smo_image);
17842
17843
17844
17845
17846
17847
17848
17849
17850
17851
17852 response = cpl_image_duplicate(spectrum);
17853 res_data = cpl_image_get_data_float(response);
17854
17855 for (i = 0; i < nx; i++) {
17856 if (eff_data[i] > 0.01 && flux_data[i] > 0.0)
17857 res_data[i] = data[i] / flux_data[i];
17858 else
17859 res_data[i] = 0.0;
17860 }
17861
17862
17863
17864
17865
17866
17867 image = cpl_image_extract(response, eff_pos + 1, 1, eff_pos + eff_count, 1);
17868
17869 smo_image = polysmooth(image, order, 50);
17870 cpl_image_delete(image);
17871
17872 smo_response = cpl_image_duplicate(response);
17873 smo_res_data = cpl_image_get_data_float(smo_response);
17874 cpl_image_copy(smo_response, smo_image, eff_pos + 1, 1);
17875
17876 cpl_image_delete(smo_image);
17877
17878 for (i = 0; i < nx; i++) {
17879 if (eff_data[i] > 0.01) {
17880 res_data[i] = 1 / res_data[i];
17881 smo_res_data[i] = 1 / smo_res_data[i];
17882 }
17883 else {
17884 res_data[i] = 0.0;
17885 smo_res_data[i] = 0.0;
17886 }
17887 }
17888
17889
17890
17891
17892
17893
17894 table = cpl_table_new(nx);
17895
17896 cpl_table_new_column(table, "WAVE", CPL_TYPE_FLOAT);
17897 cpl_table_set_column_unit(table, "WAVE", "Angstrom");
17898
17899 for (i = 0; i < nx; i++)
17900 cpl_table_set_float(table, "WAVE", i, startwave + dispersion*(i+0.5));
17901
17902 cpl_table_new_column(table, "STD_FLUX", CPL_TYPE_FLOAT);
17903 cpl_table_set_column_unit(table, "STD_FLUX",
17904 "10^(-16) erg/(cm^2 s Angstrom)");
17905 cpl_table_copy_data_float(table, "STD_FLUX", flux_data);
17906 cpl_image_delete(flux); flux = NULL;
17907
17908 cpl_table_new_column(table, "OBS_FLUX", CPL_TYPE_FLOAT);
17909 cpl_table_set_column_unit(table, "OBS_FLUX", "electron/(s Angstrom)");
17910 cpl_table_copy_data_float(table, "OBS_FLUX", data);
17911 cpl_image_delete(spectrum); spectrum = NULL;
17912
17913 cpl_table_new_column(table, "RAW_EFFICIENCY", CPL_TYPE_FLOAT);
17914 cpl_table_set_column_unit(table, "RAW_EFFICIENCY", "electron/photon");
17915 cpl_table_copy_data_float(table, "RAW_EFFICIENCY", eff_data);
17916 cpl_image_delete(efficiency); efficiency = NULL;
17917
17918 cpl_table_new_column(table, "EFFICIENCY", CPL_TYPE_FLOAT);
17919 cpl_table_set_column_unit(table, "EFFICIENCY", "electron/photon");
17920 cpl_table_copy_data_float(table, "EFFICIENCY", smo_eff_data);
17921 cpl_image_delete(smo_efficiency); smo_efficiency = NULL;
17922
17923 cpl_table_new_column(table, "RAW_RESPONSE", CPL_TYPE_FLOAT);
17924 cpl_table_set_column_unit(table, "RAW_RESPONSE",
17925 "10^(-16) erg/(cm^2 electron)");
17926 cpl_table_copy_data_float(table, "RAW_RESPONSE", res_data);
17927 cpl_image_delete(response); response = NULL;
17928
17929 cpl_table_new_column(table, "RESPONSE", CPL_TYPE_FLOAT);
17930 cpl_table_set_column_unit(table,
17931 "RESPONSE", "10^(-16) erg/(cm^2 electron)");
17932 cpl_table_copy_data_float(table, "RESPONSE", smo_res_data);
17933 cpl_image_delete(smo_response); smo_response = NULL;
17934
17935 cleanup;
17936
17937 return table;
17938 }
17939
17940 static double ksigma_vector(cpl_vector *values,
17941 double klow, double khigh, int kiter, int *good)
17942 {
17943 cpl_vector *accepted;
17944 double mean = 0.0;
17945 double sigma = 0.0;
17946 double *data = cpl_vector_get_data(values);
17947 int n = cpl_vector_get_size(values);
17948 int ngood = n;
17949 int count = 0;
17950 int i;
17951
17952
17953
17954
17955
17956
17957
17958 mean = cpl_vector_get_median(values);
17959
17960 for (i = 0; i < n; i++)
17961 sigma += (mean - data[i]) * (mean - data[i]);
17962
17963 sigma = sqrt(sigma / (n - 1));
17964
17965 while (kiter) {
17966 count = 0;
17967 for (i = 0; i < ngood; i++) {
17968 if (data[i]-mean < khigh*sigma && mean-data[i] < klow*sigma) {
17969 data[count] = data[i];
17970 ++count;
17971 }
17972 }
17973
17974 if (count == 0)
17975 break;
17976
17977
17978
17979
17980
17981
17982
17983 accepted = cpl_vector_wrap(count, data);
17984 mean = cpl_vector_get_mean(accepted);
17985 if (count > 1)
17986 sigma = cpl_vector_get_stdev(accepted);
17987 cpl_vector_unwrap(accepted);
17988
17989 if (count == ngood || count == 1)
17990 break;
17991
17992 ngood = count;
17993 --kiter;
17994 }
17995
17996 if (good)
17997 *good = ngood;
17998
17999 return mean;
18000 }
18001
18002
18021 cpl_image *mos_ksigma_stack(cpl_imagelist *imlist,
18022 double klow, double khigh, int kiter,
18023 cpl_image **good)
18024 {
18025 int ni, nx, ny, npix;
18026 cpl_image *out_ima;
18027 float *pout_ima;
18028 float *good_ima;
18029 cpl_image *image;
18030 float **data;
18031 cpl_vector *time_line;
18032 double *ptime_line;
18033 int ngood;
18034 int i, j;
18035
18036
18037 ni = cpl_imagelist_get_size(imlist);
18038
18039 image = cpl_imagelist_get(imlist, 0);
18040 nx = cpl_image_get_size_x(image);
18041 ny = cpl_image_get_size_y(image);
18042 npix = nx * ny;
18043
18044 out_ima = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
18045 pout_ima = cpl_image_get_data_float(out_ima);
18046
18047 if (good) {
18048 *good = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
18049 good_ima = cpl_image_get_data_float(*good);
18050 }
18051
18052 time_line = cpl_vector_new(ni);
18053 ptime_line = cpl_vector_get_data(time_line);
18054
18055 data = cpl_calloc(sizeof(float *), ni);
18056
18057 for (i = 0; i < ni; i++) {
18058 image = cpl_imagelist_get(imlist, i);
18059 data[i] = cpl_image_get_data_float(image);
18060 }
18061
18062 for (i = 0; i < npix; i++) {
18063 for (j = 0; j < ni; j++) {
18064 ptime_line[j] = data[j][i];
18065 }
18066 pout_ima[i] = ksigma_vector(time_line, klow, khigh, kiter, &ngood);
18067 if (good) {
18068 good_ima[i] = ngood;
18069 }
18070 }
18071
18072 cpl_free(data);
18073 cpl_vector_delete(time_line);
18074
18075 return out_ima;
18076
18077 }
18078
18079
18096 cpl_image *mos_apply_photometry(cpl_image *spectra, cpl_table *response,
18097 cpl_table *ext_table, double startwave,
18098 double dispersion, double gain,
18099 double exptime, double airmass)
18100 {
18101 cpl_image *extinction;
18102 cpl_image *outspectra;
18103 cpl_image *mapresponse;
18104 float *res_data;
18105 float *out_data;
18106 float *ext_data;
18107 int tlength, xlength, ylength;
18108 int i, j, k;
18109 double resp_startwave;
18110 double resp_endwave;
18111 int null;
18112
18113
18114 if (spectra == NULL || ext_table == NULL || response == NULL) {
18115 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
18116 return NULL;
18117 }
18118
18119
18120
18121
18122
18123 if(cpl_table_has_column(response, "RESPONSE"))
18124 cpl_table_cast_column(response, "RESPONSE", "RESPONSE_F", CPL_TYPE_FLOAT);
18125 else if(cpl_table_has_column(response, "RESPONSE_FFSED"))
18126 cpl_table_cast_column(response, "RESPONSE_FFSED", "RESPONSE_F", CPL_TYPE_FLOAT);
18127 else
18128 return NULL;
18129
18130 res_data = cpl_table_get_data_float(response, "RESPONSE_F");
18131
18132 if (res_data == NULL) {
18133 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
18134 return NULL;
18135 }
18136
18137 tlength = cpl_table_get_nrow(response);
18138 xlength = cpl_image_get_size_x(spectra);
18139 ylength = cpl_image_get_size_y(spectra);
18140
18141
18142 mapresponse = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18143 map_table(mapresponse, startwave + dispersion/2, dispersion,
18144 response, "WAVE", "RESPONSE_F");
18145 res_data = cpl_image_get_data_float(mapresponse);
18146
18147
18148
18149
18150
18151
18152 extinction = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18153 map_table(extinction, startwave + dispersion/2, dispersion,
18154 ext_table, "WAVE", "EXTINCTION");
18155
18156
18157
18158
18159
18160
18161 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
18162 cpl_image_exponential(extinction, 10.);
18163
18164 outspectra = cpl_image_duplicate(spectra);
18165
18166 ext_data = cpl_image_get_data_float(extinction);
18167 out_data = cpl_image_get_data_float(outspectra);
18168
18169 for (k = 0, i = 0; i < ylength; i++) {
18170 for (j = 0; j < xlength; j++, k++)
18171 out_data[k] *= ext_data[j] * res_data[j];
18172 }
18173
18174 cpl_image_delete(extinction);
18175 cpl_image_delete(mapresponse);
18176
18177 cpl_image_multiply_scalar(outspectra, gain / exptime / dispersion);
18178
18179
18180
18181
18182 resp_startwave = cpl_table_get(response, "WAVE", 0, &null);
18183 resp_endwave = cpl_table_get(response, "WAVE",
18184 cpl_table_get_nrow(response) -1, &null);
18185 for (j = 0; j < xlength; j++) {
18186 double this_wave = startwave + j * dispersion;
18187 if(this_wave < resp_startwave ||this_wave > resp_endwave)
18188 {
18189 for (i = 0; i < ylength; i++)
18190 out_data[j + xlength * i] = -1;
18191 }
18192 }
18193
18194 cpl_table_erase_column(response, "RESPONSE_F");
18195
18196 return outspectra;
18197 }
18198
18199
18216 cpl_image *mos_propagate_photometry_error(cpl_image *spectra,
18217 cpl_image *errors,
18218 cpl_table *response,
18219 cpl_table *ext_table,
18220 double startwave,
18221 double dispersion, double gain,
18222 double exptime, double airmass)
18223 {
18224 cpl_image *extinction;
18225 cpl_image *outerrors;
18226 cpl_image *mapresponse;
18227 cpl_image *maperror;
18228 float *err_data;
18229 float *out_data;
18230 float *ext_data;
18231 float *res_data;
18232 float *spe_data;
18233 int tlength, xlength, ylength;
18234 int i, j, k;
18235
18236
18237 if (errors == NULL || ext_table == NULL || response == NULL) {
18238 cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
18239 return NULL;
18240 }
18241
18242 if (!cpl_table_has_column(response, "ERROR")) {
18243 return mos_apply_photometry(errors, response, ext_table, startwave,
18244 dispersion, gain, exptime, airmass);
18245 }
18246
18247 cpl_table_cast_column(response, "RESPONSE", "RESPONSE_F", CPL_TYPE_FLOAT);
18248 res_data = cpl_table_get_data_float(response, "RESPONSE_F");
18249
18250 if (res_data == NULL) {
18251 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
18252 return NULL;
18253 }
18254
18255 err_data = cpl_table_get_data_float(response, "ERROR");
18256
18257 if (err_data == NULL) {
18258 cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND);
18259 return NULL;
18260 }
18261
18262 tlength = cpl_table_get_nrow(response);
18263 xlength = cpl_image_get_size_x(errors);
18264 ylength = cpl_image_get_size_y(errors);
18265
18266 if (xlength != tlength) {
18267 mapresponse = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18268 map_table(mapresponse, startwave + dispersion/2, dispersion,
18269 response, "WAVE", "RESPONSE_F");
18270 res_data = cpl_image_get_data_float(mapresponse);
18271
18272 maperror = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18273 map_table(maperror, startwave + dispersion/2, dispersion,
18274 response, "WAVE", "ERROR");
18275 err_data = cpl_image_get_data_float(maperror);
18276 }
18277
18278
18279
18280
18281
18282
18283 extinction = cpl_image_new(xlength, 1, CPL_TYPE_FLOAT);
18284 map_table(extinction, startwave + dispersion/2, dispersion,
18285 ext_table, "WAVE", "EXTINCTION");
18286
18287
18288
18289
18290
18291
18292 cpl_image_multiply_scalar(extinction, 0.4 * airmass);
18293 cpl_image_exponential(extinction, 10.);
18294
18295 outerrors = cpl_image_duplicate(errors);
18296
18297 ext_data = cpl_image_get_data_float(extinction);
18298 out_data = cpl_image_get_data_float(outerrors);
18299 spe_data = cpl_image_get_data_float(spectra);
18300
18301 for (k = 0, i = 0; i < ylength; i++) {
18302 for (j = 0; j < xlength; j++, k++) {
18303 out_data[k] = ext_data[j] *
18304 sqrt(err_data[j] * err_data[j] * spe_data[k] * spe_data[k] +
18305 res_data[j] * res_data[j] * out_data[k] * out_data[k]);
18306 }
18307 }
18308
18309 cpl_image_delete(extinction);
18310 if (xlength != tlength) {
18311 cpl_image_delete(maperror);
18312 }
18313
18314 cpl_image_multiply_scalar(outerrors, gain / exptime / dispersion);
18315
18316 cpl_table_erase_column(response, "RESPONSE_F");
18317 return outerrors;
18318 }
18319
18320
18396 int mos_check_polarisation(cpl_image *q_image, cpl_image *q_error,
18397 cpl_image *u_image, cpl_image *u_error,
18398 double startwave, double dispersion,
18399 double band, cpl_table *pol_sta,
18400 double ra, double dec, char *filter,
18401 int *polarisation,
18402 double *p_offset, double *p_error,
18403 double *a_offset, double *a_error)
18404 {
18405 cpl_table *standard;
18406 cpl_image *q_noise;
18407 cpl_image *q_signal;
18408 cpl_image *u_noise;
18409 cpl_image *u_signal;
18410 cpl_image *noise;
18411 double *q_ndata;
18412 double *q_sdata;
18413 double *u_ndata;
18414 double *u_sdata;
18415 double arctol = 0.5;
18416 double mindist;
18417 double cwave;
18418 double bwave[] = {3650., 4450., 5510., 6580., 8060};
18419 char *bands = "UBVRI";
18420 char p_label[] = {' ', 'p', '\0'};
18421 char dp_label[] = {' ', 'd', 'p', '\0'};
18422 char a_label[] = {' ', 'a', '\0'};
18423 char da_label[] = {' ', 'd', 'a', '\0'};
18424 int nbands = strlen(bands);
18425 int selected;
18426 int first, last, count, center;
18427 int nx;
18428 cpl_size col, row;
18429 int i, found, closest;
18430 int pband;
18431 int polarised;
18432 double q_obs;
18433 double q_err;
18434 double u_obs;
18435 double u_err;
18436 double p_obs;
18437 double p_err;
18438 double p_ref;
18439 double dp_ref;
18440 double a_obs;
18441 double a_err;
18442 double a_ref;
18443 double da_ref;
18444
18445
18446 *filter = '\0';
18447 *polarisation = 0;
18448 *p_offset = 0.0;
18449 *p_error = 0.0;
18450 *a_offset = 0.0;
18451 *a_error = 0.0;
18452
18453
18454
18455
18456
18457 cpl_table_select_all(pol_sta);
18458 cpl_table_and_selected_double(pol_sta, "COORD_RA", CPL_GREATER_THAN,
18459 ra-arctol);
18460 cpl_table_and_selected_double(pol_sta, "COORD_RA", CPL_LESS_THAN,
18461 ra+arctol);
18462 cpl_table_and_selected_double(pol_sta, "COORD_DEC", CPL_GREATER_THAN,
18463 dec-arctol);
18464 selected =
18465 cpl_table_and_selected_double(pol_sta, "COORD_DEC", CPL_LESS_THAN,
18466 dec+arctol);
18467
18468 if (selected == 0) {
18469 cpl_msg_warning(cpl_func, "No standard star found in FOV");
18470 return 1;
18471 }
18472
18473 if (selected > 1) {
18474 cpl_msg_warning(cpl_func,
18475 "Ambiguity: %d standard stars found in FOV", selected);
18476 return 1;
18477 }
18478
18479 standard = cpl_table_extract_selected(pol_sta);
18480
18481 cpl_msg_info(cpl_func, "Standard star: %s",
18482 cpl_table_get_string(standard, "name", 0));
18483
18484
18485
18486
18487
18488 polarised = cpl_table_get_int(standard, "polarised", 0, NULL);
18489
18490 cpl_msg_info(cpl_func, "This star is%sexpected to be polarised",
18491 polarised ? " " : " not ");
18492
18493
18494
18495
18496
18497
18498
18499
18500
18501 nx = cpl_image_get_size_x(q_error);
18502
18503 noise = cpl_image_collapse_median_create(q_error, 1, 0, 0);
18504 cpl_image_get_minpos(noise, &col, &row);
18505
18506 cpl_image_delete(noise);
18507
18508 if (col != 1) {
18509 cpl_table_delete(standard);
18510 cpl_msg_error(cpl_func,
18511 "Assertion failure!!! col = %"CPL_SIZE_FORMAT" (it should be 1)", col);
18512 return 1;
18513 }
18514
18515 q_signal = cpl_image_extract(q_image, 1, row, nx, row);
18516 q_noise = cpl_image_extract(q_error, 1, row, nx, row);
18517 u_signal = cpl_image_extract(u_image, 1, row, nx, row);
18518 u_noise = cpl_image_extract(u_error, 1, row, nx, row);
18519
18520 q_sdata = cpl_image_get_data_double(q_signal);
18521 q_ndata = cpl_image_get_data_double(q_noise);
18522 u_sdata = cpl_image_get_data_double(u_signal);
18523 u_ndata = cpl_image_get_data_double(u_noise);
18524
18525
18526
18527
18528
18529
18530 first = -1;
18531 last = nx = cpl_image_get_size_x(q_signal);
18532 for (i = 0; i < nx; i++) {
18533 if (first < 0) {
18534 if (q_ndata[i] > 0.0) {
18535 first = i;
18536 }
18537 }
18538 else {
18539 if (q_ndata[i] <= 0.0) {
18540 last = i - 1;
18541 break;
18542 }
18543 }
18544 }
18545
18546 count = last - first + 1;
18547
18548 if (first < 0 || count < band) {
18549 cpl_table_delete(standard);
18550 cpl_image_delete(q_signal);
18551 cpl_image_delete(q_noise);
18552 cpl_image_delete(u_signal);
18553 cpl_image_delete(u_noise);
18554 cpl_msg_warning(cpl_func, "Too short spectrum (%d pixels)", count);
18555 return 1;
18556 }
18557
18558 center = (first + last) / 2;
18559 cwave = startwave + dispersion * center;
18560
18561
18562
18563
18564
18565
18566 found = 0;
18567 for (i = 0; i < nbands; i++) {
18568 p_label[0] = bands[i];
18569 if (cpl_table_is_valid(standard, p_label, 0)) {
18570 if (found == 0) {
18571 found = 1;
18572 mindist = fabs(bwave[i] - cwave);
18573 closest = i;
18574 }
18575 else if (mindist > fabs(bwave[i] - cwave)) {
18576 mindist = fabs(bwave[i] - cwave);
18577 closest = i;
18578 }
18579 }
18580 }
18581
18582 if (!found) {
18583 cpl_table_delete(standard);
18584 cpl_image_delete(q_signal);
18585 cpl_image_delete(q_noise);
18586 cpl_image_delete(u_signal);
18587 cpl_image_delete(u_noise);
18588 cpl_msg_warning(cpl_func, "No reference value available");
18589 return 1;
18590 }
18591
18592 center = (bwave[closest] - startwave) / dispersion;
18593 cwave = bwave[closest];
18594
18595
18596
18597
18598
18599
18600
18601 pband = floor(band / dispersion);
18602
18603 if (center - pband/2 < first || center + pband/2 > last) {
18604 cpl_table_delete(standard);
18605 cpl_image_delete(q_signal);
18606 cpl_image_delete(q_noise);
18607 cpl_image_delete(u_signal);
18608 cpl_image_delete(u_noise);
18609 cpl_msg_warning(cpl_func, "No reference value available");
18610 return 1;
18611 }
18612
18613 first = center - pband/2;
18614 last = center + pband/2;
18615
18616
18617
18618
18619
18620
18621 p_label[0] = bands[closest];
18622 dp_label[0] = bands[closest];
18623 a_label[0] = bands[closest];
18624 da_label[0] = bands[closest];
18625
18626 p_ref = cpl_table_get(standard, p_label, 0, NULL);
18627 dp_ref = cpl_table_get(standard, dp_label, 0, NULL);
18628 a_ref = cpl_table_get(standard, a_label, 0, NULL);
18629 da_ref = cpl_table_get(standard, da_label, 0, NULL);
18630
18631 cpl_msg_info(cpl_func,
18632 "The expected polarisation is %.2f +- %.2f %%",
18633 p_ref, dp_ref);
18634
18635 if (polarised) {
18636 cpl_msg_info(cpl_func,
18637 "The expected polarisation angle is %.2f +- %.2f degrees",
18638 a_ref, da_ref);
18639 }
18640
18641
18642
18643
18644
18645 q_obs = cpl_image_get_median_window(q_image, first, 1, last, 1);
18646 q_err = cpl_image_get_median_window(q_error, first, 1, last, 1);
18647 u_obs = cpl_image_get_median_window(u_image, first, 1, last, 1);
18648 u_err = cpl_image_get_median_window(u_error, first, 1, last, 1);
18649
18650
18651
18652
18653
18654 p_obs = sqrt(q_obs * q_obs + u_obs * u_obs);
18655 p_err = CPL_MATH_SQRT1_2 * 0.5 * (q_err + u_err);
18656
18657
18658
18659
18660
18661 a_obs = 0.0;
18662 if (polarised) {
18663 if (fabs(q_obs) < 0.00001) {
18664 if (u_obs > 0.0) {
18665 a_obs = 45.0;
18666 }
18667 else {
18668 a_obs = 135.0;
18669 }
18670 }
18671 else {
18672 a_obs = 0.5 * atan(u_obs / q_obs) * 180 / CPL_MATH_PI;
18673 if (q_obs > 0.0) {
18674 if (u_obs < 0.0) {
18675 a_obs += 180.;
18676 }
18677 }
18678 else {
18679 a_obs += 90.;
18680 }
18681 }
18682 }
18683
18684
18685
18686
18687
18688 a_err = 0.0;
18689 if (polarised) {
18690 a_err = sqrt(q_obs*q_obs*u_err*u_err + u_obs*u_obs*q_err*q_err)
18691 / (p_obs * p_obs)
18692 * 90 / CPL_MATH_PI;
18693 }
18694
18695 p_obs *= 100;
18696 p_err *= 100;
18697 cpl_msg_info(cpl_func,
18698 "The measured polarisation is %.2f +- %.2f %%",
18699 p_obs, p_err);
18700
18701 if (polarised) {
18702 cpl_msg_info(cpl_func,
18703 "The measured polarisation angle is %.2f +- %.2f degrees",
18704 a_obs, a_err);
18705 }
18706
18707 *filter = bands[closest];
18708 *polarisation = polarised;
18709
18710 if (polarised) {
18711 *p_offset = (p_obs - p_ref) / p_ref;
18712 *p_error = sqrt(p_err * p_err + dp_ref * dp_ref) / p_ref;
18713 }
18714 else {
18715 *p_offset = p_obs - p_ref;
18716 *p_error = sqrt(p_err * p_err + dp_ref * dp_ref);
18717 }
18718
18719 *a_offset = a_obs - a_ref;
18720 *a_error = sqrt(a_err*a_err + da_ref*da_ref);
18721
18722 return 0;
18723
18724 }
18725
18726
18758 int mos_compute_offset(cpl_table *reference, cpl_table *objects, double *offset)
18759 {
18760 cpl_array *offsets;
18761 int noffset;
18762 int nslits = cpl_table_get_nrow(reference);
18763 int *nref;
18764 int *nobj;
18765 int corr, maxcorr;
18766 int best_shift;
18767 int i, j, k;
18768
18769 cpl_error_code status = CPL_ERROR_NONE;
18770
18771
18772 *offset = 0.0;
18773
18774 if (objects == NULL)
18775 return CPL_ERROR_NULL_INPUT;
18776
18777 if (nslits != cpl_table_get_nrow(objects))
18778 return CPL_ERROR_INCOMPATIBLE_INPUT;
18779
18780 nref = fors_get_nobjs_perslit(reference);
18781 nobj = fors_get_nobjs_perslit(objects);
18782
18783 noffset = 0;
18784 for (i = 0; i < nslits; i++)
18785 noffset += nobj[i];
18786
18787 if (noffset == 0) {
18788 cpl_free(nref);
18789 cpl_free(nobj);
18790 return CPL_ERROR_DATA_NOT_FOUND;
18791 }
18792
18793 noffset = 0;
18794 for (i = 0; i < nslits; i++)
18795 noffset += nref[i];
18796
18797 if (noffset == 0) {
18798 cpl_free(nref);
18799 cpl_free(nobj);
18800 return CPL_ERROR_DATA_NOT_FOUND;
18801 }
18802
18803 offsets = cpl_array_new(noffset, CPL_TYPE_DOUBLE);
18804
18805 noffset = 0;
18806
18807 for (i = 0; i < nslits; i++) {
18808 if (nref[i] > 0 && nobj[i] > 0) {
18809 double shift;
18810 int length = cpl_table_get_int(objects, "length", i, NULL);
18811 double ytop = cpl_table_get_double(objects, "xtop", i, NULL);
18812 double ybottom = cpl_table_get_double(objects, "xbottom", i, NULL);
18813 int *aref = cpl_calloc(length, sizeof(int));
18814 int *aobj = cpl_calloc(length, sizeof(int));
18815 float *pref = cpl_calloc(nref[i], sizeof(float));
18816 float *pobj = cpl_calloc(nobj[i], sizeof(float));
18817
18818 for (j = 0; j < nref[i]; j++) {
18819 pref[j] = fors_get_object_position(reference, i, j + 1);
18820 aref[(int)pref[j]] = 1;
18821 }
18822
18823 for (j = 0; j < nobj[i]; j++) {
18824 pobj[j] = fors_get_object_position(objects, i, j + 1);
18825 aobj[(int)pobj[j]] = 1;
18826 }
18827
18828
18829
18830
18831
18832 aref[0] = 0;
18833 aref[length - 1] = 0;
18834 aobj[0] = 0;
18835 aobj[length - 1] = 0;
18836
18837
18838
18839
18840
18841
18842
18843
18844
18845
18846
18847
18848
18849
18850
18851
18852
18853
18854 maxcorr = 0;
18855 best_shift = length;
18856
18857 for (shift = length/2, j = 0; j <= length; shift--, j++) {
18858 int rstart, ostart, count;
18859
18860 if (shift > 0) {
18861 rstart = shift;
18862 ostart = 0;
18863 count = length - shift;
18864 }
18865 else {
18866 rstart = 0;
18867 ostart = -shift;
18868 count = length + shift;
18869 }
18870
18871 corr = 0;
18872 for (k = 0; k < count; k++) {
18873 corr += aref[rstart + k] * aobj[ostart + k];
18874 }
18875
18876 if (maxcorr < corr) {
18877 maxcorr = corr;
18878 best_shift = shift;
18879 }
18880 }
18881
18882 if (best_shift == length) {
18883
18884 cpl_free(aref);
18885 cpl_free(aobj);
18886 cpl_free(pref);
18887 cpl_free(pobj);
18888 continue;
18889 }
18890
18891
18892 for (j = 0; j < nref[i]; j++) {
18893 for (k = 0; k < nobj[i]; k++) {
18894 if (fabs(pref[j] - pobj[k] - best_shift) < 2) {
18895 double ccd_offset = (pref[j] - pobj[k])
18896 * (ytop - ybottom)
18897 / length;
18898
18899
18900
18901
18902
18903
18904
18905 cpl_array_set(offsets, noffset, ccd_offset);
18906 noffset++;
18907 break;
18908 }
18909 }
18910 }
18911
18912 cpl_free(aref);
18913 cpl_free(aobj);
18914 cpl_free(pref);
18915 cpl_free(pobj);
18916 }
18917
18918
18919 }
18920
18921 cpl_free(nref);
18922 cpl_free(nobj);
18923
18924
18925 if (noffset > 0) {
18926 if (noffset % 2) {
18927 *offset = cpl_array_get_median(offsets);
18928 }
18929 else {
18930 double *a = cpl_malloc(sizeof(double) * noffset);
18931 for (i = 0; i < noffset; i++) {
18932 a[i] = cpl_array_get_double(offsets, i, NULL);
18933 }
18934 *offset = (fors_tools_get_kth_double(a, noffset, (noffset-1)/2) +
18935 fors_tools_get_kth_double(a, noffset, (noffset/2))) / 2.0;
18936 cpl_free(a);
18937 }
18938 }
18939 else
18940 status = CPL_ERROR_DATA_NOT_FOUND;
18941
18942
18943 cpl_array_delete(offsets);
18944
18945 return status;
18946
18947 }
18948
18949
18961 cpl_error_code mos_image_shift(cpl_image *image, double dx, double dy)
18962 {
18963 cpl_image *source;
18964 int nx = cpl_image_get_size_x(image);
18965 int ny = cpl_image_get_size_y(image);
18966 float *idata;
18967 float *sdata;
18968 int i, j, pos;
18969 double xpos, ypos, xfrac, yfrac;
18970 int xint, yint;
18971
18972
18973 if (fabs(dx) >= nx || fabs(dy) >= ny)
18974 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
18975
18976 source = cpl_image_duplicate(image);
18977 idata = cpl_image_get_data_float(image);
18978 sdata = cpl_image_get_data_float(source);
18979
18980
18981
18982
18983
18984 yfrac = - dy - floor(- dy);
18985 xfrac = - dx - floor(- dx);
18986
18987 for (pos = 0, j = 0; j < ny; j++) {
18988 ypos = j - dy;
18989 yint = floor(ypos);
18990 for (i = 0; i < nx; i++) {
18991 xpos = i - dx;
18992 xint = floor(xpos);
18993 if (xint < 0 || yint < 0 || xint > nx - 2 || yint > ny - 2) {
18994 idata[pos] = 0.0;
18995 }
18996 else {
18997 idata[pos] = sdata[xint + nx*yint] * (1 - xfrac) * (1 - yfrac)
18998 + sdata[xint + 1 + nx*yint] * xfrac * (1 - yfrac)
18999 + sdata[xint + nx*(yint + 1)] * (1 - xfrac) * yfrac
19000 + sdata[xint + 1 + nx*(yint + 1)] * xfrac * yfrac;
19001 }
19002 pos++;
19003 }
19004 }
19005
19006 cpl_image_delete(source);
19007
19008 return CPL_ERROR_NONE;
19009 }
19010
19022 int mos_slit_closest_to_center(cpl_table *slits, int nx, int ny)
19023 {
19024 #ifdef CPL_SIZE_FORMAT
19025 cpl_size row;
19026 #else
19027 int row;
19028 #endif
19029
19030 cpl_table_duplicate_column(slits, "x", slits, "xtop");
19031 cpl_table_add_columns(slits, "x", "xbottom");
19032 cpl_table_divide_scalar(slits, "x", 2);
19033 cpl_table_subtract_scalar(slits, "x", nx/2);
19034 cpl_table_multiply_columns(slits, "x", "x");
19035
19036 cpl_table_duplicate_column(slits, "y", slits, "ytop");
19037 cpl_table_add_columns(slits, "y", "ybottom");
19038 cpl_table_divide_scalar(slits, "y", 2);
19039 cpl_table_subtract_scalar(slits, "y", ny/2);
19040 cpl_table_multiply_columns(slits, "y", "y");
19041
19042 cpl_table_add_columns(slits, "x", "y");
19043 cpl_table_get_column_minpos(slits, "x", &row);
19044
19045 cpl_table_erase_column(slits, "x");
19046 cpl_table_erase_column(slits, "y");
19047
19048 return row;
19049 }
19050
19070 cpl_error_code mos_extract_flux(cpl_image *image, cpl_table *slits,
19071 double xwidth, double ywidth,
19072 int dx, double gain, double *o_flux, double *o_err)
19073 {
19074 int nx = cpl_image_get_size_x(image);
19075 int ny = cpl_image_get_size_y(image);
19076 int slit = mos_slit_closest_to_center(slits, nx, ny);
19077 int ytop = (int)cpl_table_get(slits, "ytop", slit, NULL);
19078 int ybottom = (int)cpl_table_get(slits, "ybottom", slit, NULL);
19079 int dy = ytop - ybottom;
19080 int xcenter = (int)((cpl_table_get(slits, "xtop", slit, NULL) +
19081 cpl_table_get(slits, "xbottom", slit, NULL)) / 2);
19082 int xleft = xcenter - dx;
19083 int xright = xcenter + dx + 1;
19084 double area = xwidth * ywidth;
19085 int npix = (2*dx + 1) * dy;
19086 int count = 0;
19087 float *data = cpl_image_get_data_float(image);
19088 double flux = 0.0;
19089 double error = 0.0;
19090 int satur = 60000;
19091 int x, y;
19092
19093
19094 if (cpl_table_has_column(slits, "ywidth")) {
19095 area = cpl_table_get(slits, "xwidth", slit, NULL)
19096 * cpl_table_get(slits, "ywidth", slit, NULL);
19097 }
19098
19099 *o_flux = 0.0;
19100 *o_err = 0.0;
19101
19102 if (xleft < 0)
19103 xleft = 0;
19104
19105 if (xleft > nx)
19106 xleft = nx;
19107
19108 if (xright < 0)
19109 xright = 0;
19110
19111 if (xright > nx)
19112 xright = nx;
19113
19114 if (ytop < 0)
19115 ytop = 0;
19116
19117 if (ytop > ny)
19118 ytop = ny;
19119
19120 if (ybottom < 0)
19121 ybottom = 0;
19122
19123 if (ybottom > ny)
19124 ybottom = ny;
19125
19126 count = (xright - xleft) * (ytop - ybottom);
19127
19128 if (count == 0)
19129 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
19130
19131 count = 0;
19132
19133 for (y = ybottom; y < ytop; y++) {
19134 for (x = xleft; x < xright; x++) {
19135 double value = data[x + y * nx];
19136 if (value < satur) {
19137 flux += value;
19138 count++;
19139 }
19140 }
19141 }
19142
19143 if (count == 0)
19144 return CPL_ERROR_DIVISION_BY_ZERO;
19145
19146 error = sqrt(flux/gain);
19147
19148
19149
19150
19151
19152 flux *= (float)npix / count;
19153 error *= (float)npix / count;
19154
19155 flux /= area;
19156 error /= area;
19157
19158 *o_flux = flux;
19159 *o_err = error;
19160
19161 return CPL_ERROR_NONE;
19162 }
19163
19164
19187 cpl_error_code mos_extract_flux_mapped(cpl_image *image, cpl_table *slits,
19188 double xwidth, double ywidth,
19189 double lambda, double startwave,
19190 double dispersion, int dx, double gain,
19191 double *o_flux, double *o_err)
19192 {
19193 int nx = cpl_image_get_size_x(image);
19194 int ny = cpl_image_get_size_y(image);
19195 int slit = mos_slit_closest_to_center(slits, nx, ny);
19196 int dy = (int)cpl_table_get(slits, "length", slit, NULL);
19197 int ybottom = (int)cpl_table_get(slits, "position", slit, NULL);
19198 int ytop = ybottom + dy;
19199 int xcenter = (int)floor((lambda - startwave) / dispersion + 0.5);
19200 int xleft = xcenter - dx;
19201 int xright = xcenter + dx + 1;
19202 double area = xwidth * ywidth;
19203 int npix = (2*dx + 1) * dy;
19204 int count = 0;
19205 float *data = cpl_image_get_data_float(image);
19206 double flux = 0.0;
19207 double error = 0.0;
19208 int satur = 60000;
19209 int x, y;
19210
19211
19212 if (cpl_table_has_column(slits, "ywidth")) {
19213 area = cpl_table_get(slits, "xwidth", slit, NULL)
19214 * cpl_table_get(slits, "ywidth", slit, NULL);
19215 }
19216
19217 *o_flux = 0.0;
19218 *o_err = 0.0;
19219
19220 if (xleft < 0)
19221 xleft = 0;
19222
19223 if (xleft > nx)
19224 xleft = nx;
19225
19226 if (xright < 0)
19227 xright = 0;
19228
19229 if (xright > nx)
19230 xright = nx;
19231
19232 if (ytop < 0)
19233 ytop = 0;
19234
19235 if (ytop > ny)
19236 ytop = ny;
19237
19238 if (ybottom < 0)
19239 ybottom = 0;
19240
19241 if (ybottom > ny)
19242 ybottom = ny;
19243
19244 count = (xright - xleft) * (ytop - ybottom);
19245
19246 if (count == 0)
19247 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
19248
19249 count = 0;
19250
19251 for (y = ybottom; y < ytop; y++) {
19252 for (x = xleft; x < xright; x++) {
19253 double value = data[x + y * nx];
19254 if (value < satur) {
19255 flux += value;
19256 count++;
19257 }
19258 }
19259 }
19260
19261 if (count == 0)
19262 return CPL_ERROR_DIVISION_BY_ZERO;
19263
19264 error = sqrt(flux/gain);
19265
19266
19267
19268
19269
19270 flux *= (float)npix / count;
19271 error *= (float)npix / count;
19272
19273 flux /= area;
19274 error /= area;
19275
19276 *o_flux = flux;
19277 *o_err = error;
19278
19279 return CPL_ERROR_NONE;
19280
19281 }
19282
19283
19297 int mos_median_in_slit(cpl_table *table, cpl_table *slits, int slit,
19298 char *label, double *mvalue)
19299 {
19300 int position = cpl_table_get_int(slits, "position", slit, NULL);
19301 int length = cpl_table_get_int(slits, "length", slit, NULL);
19302 cpl_table *tmp = cpl_table_extract(table, position, length);
19303
19304 *mvalue = cpl_table_get_column_median(tmp, label);
19305 cpl_table_delete(tmp);
19306
19307 if (cpl_error_get_code() != CPL_ERROR_NONE)
19308 return 1;
19309
19310 return 0;
19311 }
19312
19313
19325 cpl_image *mos_image_filter_median(cpl_image *image, int nx, int ny)
19326 {
19327 cpl_mask *kernel = cpl_mask_new(nx, ny);
19328 cpl_image *filtered = cpl_image_new(cpl_image_get_size_x(image),
19329 cpl_image_get_size_y(image),
19330 cpl_image_get_type(image));
19331
19332 cpl_mask_not(kernel);
19333 cpl_image_filter_mask(filtered, image, kernel,
19334 CPL_FILTER_MEDIAN, CPL_BORDER_FILTER);
19335 cpl_mask_delete(kernel);
19336
19337 return filtered;
19338 }
19339
19340 int fors_mos_is_lss_like(cpl_table *maskslits, int nslits_out_det)
19341 {
19342 int treat_as_lss = 1;
19343 double mxpos = cpl_table_get_column_median(maskslits, "xtop");
19344 double * slit_xpos = cpl_table_get_data_double(maskslits, "xtop");
19345 cpl_size nslits = cpl_table_get_nrow(maskslits);
19346
19347
19348
19349 if(nslits_out_det != 0)
19350 return 0;
19351
19352 for (cpl_size i = 0; i < nslits; i++) {
19353 if (fabs(mxpos-slit_xpos[i]) > 0.01) {
19354 treat_as_lss = 0;
19355 break;
19356 }
19357 }
19358 return treat_as_lss;
19359 }