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 <string.h>
00033 #include <math.h>
00034
00035 #include <cxstring.h>
00036 #include <cxmemory.h>
00037
00038 #include <cpl_image.h>
00039 #include <cpl_vector.h>
00040 #include <cpl_matrix.h>
00041 #include <cpl_mask.h>
00042 #include <cpl_parameterlist.h>
00043 #include <cpl_msg.h>
00044
00045 #include "gimacros.h"
00046 #include "gialias.h"
00047 #include "giarray.h"
00048 #include "giimage.h"
00049 #include "gitable.h"
00050 #include "gimatrix.h"
00051 #include "giarray.h"
00052 #include "gimask.h"
00053 #include "gimath.h"
00054 #include "gimessages.h"
00055 #include "giutils.h"
00056 #include "gilocalize.h"
00057 #include "gidebug.h"
00058
00059
00060
00069
00070
00071
00072
00073 static const cxchar* _task = "giraffe_localize_spectra";
00074
00075
00076
00077
00078
00079
00080 enum GiLocalizeMethod
00081 {
00082 GILOCALIZE_HALF_WIDTH,
00083 GILOCALIZE_BARYCENTER
00084 };
00085
00086 typedef enum GiLocalizeMethod GiLocalizeMethod;
00087
00088
00089
00090
00091
00092
00093 enum GiThresholdMethod
00094 {
00095 GILOCALIZE_THRESHOLD_GLOBAL,
00096 GILOCALIZE_THRESHOLD_LOCAL,
00097 GILOCALIZE_THRESHOLD_ROW
00098 };
00099
00100 typedef enum GiThresholdMethod GiThresholdMethod;
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 inline static cxbool
00137 _giraffe_validate_pixel(cxint *pixels, cxint xsize, cxint ysize,
00138 cxint xpos, cxint ypos, cxint xwidth, cxint ywidth,
00139 cxsize count)
00140 {
00141
00142 cxint i;
00143 cxint xstart = xpos - xwidth;
00144 cxint ystart = ypos - ywidth;
00145 cxint xend = xpos + xwidth;
00146 cxint yend = ypos + ywidth;
00147
00148 cxsize _count = 0;
00149
00150
00151
00152
00153
00154
00155
00156 xstart = CX_MAX(0, xstart);
00157 ystart = CX_MAX(0, ystart);
00158
00159 xend = CX_MIN(xsize - 1, xend);
00160 yend = CX_MIN(ysize - 1, yend);
00161
00162 xwidth = CX_MAX(xwidth,1 );
00163 ywidth = CX_MAX(ywidth,1 );
00164
00165
00166
00167
00168
00169
00170
00171 for (i = ystart; i <= yend; i++) {
00172
00173 cxint j;
00174 cxint row;
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 if (i == ypos) {
00185 continue;
00186 }
00187
00188 row = i * xsize;
00189
00190 for (j = xstart; j <= xend; j++) {
00191 if (pixels[row + j]) {
00192 ++_count;
00193 }
00194
00195 if (_count >= count) {
00196 return 1;
00197 }
00198 }
00199
00200 }
00201
00202 return 0;
00203
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234 inline static cpl_matrix*
00235 _giraffe_fit_border(cpl_matrix* mborder, cpl_matrix* mbase,
00236 cpl_matrix* mxok, cxint nspectra, cxdouble sigma,
00237 cxint niter, cxdouble mfrac, cpl_matrix* mcoeff)
00238 {
00239
00240 const cxchar* const fctid = "_giraffe_fit_border";
00241
00242 register cxint x = 0;
00243 register cxint naccept = 0;
00244 register cxint ntotal = 0;
00245 register cxint iteration = 0;
00246 register cxint nx = cpl_matrix_get_ncol(mbase);
00247 register cxint yorder = cpl_matrix_get_nrow(mbase);
00248 register cxint nxok = cpl_matrix_get_nrow(mxok);
00249
00250 register cxdouble ratio = 1.0;
00251
00252 cpl_matrix* mtmp = NULL;
00253 cpl_matrix* yraw = NULL;
00254 cpl_matrix* ydiff = NULL;
00255 cpl_matrix* mfit = NULL;
00256 cpl_matrix* coeffs = NULL;
00257
00258
00259
00260 if (nxok < yorder) {
00261 cpl_error_set(fctid, CPL_ERROR_INCOMPATIBLE_INPUT);
00262
00263 GIDEBUG(gi_warning("%s: not enough points mxok[%d] for %d order fit",
00264 fctid, nxok, yorder));
00265
00266 return NULL;
00267 }
00268
00269
00270
00271
00272
00273
00274 yraw = cpl_matrix_new(1, nxok);
00275 ydiff = cpl_matrix_new(nxok, 1);
00276
00277 mtmp = cpl_matrix_duplicate(mxok);
00278
00279
00280
00281
00282
00283 for (x = 0; x < nxok; x++) {
00284 cxdouble data = cpl_matrix_get(mborder, x, nspectra);
00285 cpl_matrix_set(yraw, 0, x, data);
00286 }
00287
00288
00289
00290
00291
00292
00293 ntotal = nxok;
00294 naccept = ntotal;
00295
00296 while (naccept > 0 && iteration < niter && ratio > mfrac) {
00297
00298 register cxint k = 0;
00299 register cxint l = 0;
00300
00301 register cxdouble ysigma = 0.;
00302
00303 cpl_matrix* rawbase = giraffe_chebyshev_base1d(0., nx, yorder, mtmp);
00304 cx_assert(rawbase != NULL);
00305
00306 if (coeffs != NULL) {
00307 cpl_matrix_delete(coeffs);
00308 }
00309
00310 coeffs = giraffe_matrix_leastsq(rawbase, yraw);
00311 if (coeffs == NULL) {
00312 gi_warning("%s: error in giraffe_matrix_leastsq(), spectrum %d",
00313 fctid, nspectra);
00314 break;
00315 }
00316
00317 cpl_matrix_delete(rawbase);
00318 rawbase = NULL;
00319
00320 if (mfit != NULL) {
00321 cpl_matrix_delete(mfit);
00322 }
00323
00324 mfit = cpl_matrix_product_create(coeffs, mbase);
00325
00326 for (x = 0; x < cpl_matrix_get_nrow(ydiff); x++) {
00327
00328 cxint xok = (cxint) cpl_matrix_get(mtmp, x, 0);
00329
00330 cxdouble diff =
00331 cpl_matrix_get(yraw, 0, x) - cpl_matrix_get(mfit, 0, xok);
00332
00333
00334 cpl_matrix_set(ydiff, x , 0, diff);
00335
00336 }
00337
00338 ysigma = sigma * giraffe_matrix_sigma_mean(ydiff, 0.);
00339
00340
00341
00342
00343
00344
00345 k = 0;
00346 for (l = 0; l < cpl_matrix_get_nrow(ydiff); l++) {
00347
00348 if (fabs(cpl_matrix_get(ydiff, l, 0)) <= ysigma) {
00349
00350 cxint xok = cpl_matrix_get(mtmp, l, 0);
00351 cxdouble data = cpl_matrix_get(yraw, 0, l);
00352
00353 cpl_matrix_set(mtmp, k, 0, xok);
00354 cpl_matrix_set(yraw, 0, k, data);
00355
00356 ++k;
00357 }
00358
00359 }
00360
00361
00362
00363
00364
00365
00366 if (k == naccept) {
00367 break;
00368 }
00369
00370
00371
00372
00373
00374
00375 naccept = k;
00376 ratio = (cxdouble) naccept / (cxdouble) ntotal;
00377
00378 GIDEBUG(gi_message("Iteration %d: Sigma %f, accepted bins: %d, "
00379 "rejected %d\n", iteration, ysigma, naccept,
00380 ntotal - naccept));
00381
00382
00383
00384
00385
00386 cpl_matrix_resize(mtmp, 0,
00387 naccept - cpl_matrix_get_nrow(mtmp), 0, 0);
00388 cpl_matrix_resize(yraw, 0,
00389 0, 0, naccept - cpl_matrix_get_ncol(yraw));
00390 cpl_matrix_resize(ydiff, 0,
00391 naccept - cpl_matrix_get_nrow(ydiff), 0, 0);
00392
00393 iteration++;
00394 }
00395
00396 if (coeffs != NULL) {
00397 register cxint l;
00398
00399 for (l = 0; l < cpl_matrix_get_nrow(mcoeff); l++) {
00400 cpl_matrix_set(mcoeff, l, 0, cpl_matrix_get(coeffs, 0, l));
00401 }
00402 }
00403
00404
00405
00406
00407
00408
00409 cpl_matrix_delete(coeffs);
00410 cpl_matrix_delete(ydiff);
00411 cpl_matrix_delete(yraw);
00412 cpl_matrix_delete(mtmp);
00413
00414 return mfit;
00415
00416 }
00417
00418
00419 inline static cpl_image*
00420 _giraffe_filter_gauss1d(const cpl_image* image, cxint radius, cxdouble width)
00421 {
00422
00423 cxdouble w2 = width * width;
00424
00425 cxint i = 0;
00426
00427 cpl_matrix* kernel = cpl_matrix_new(1, 2 * radius + 1);
00428
00429 cpl_image* fimage = NULL;
00430
00431
00432 if (kernel == NULL) {
00433 return NULL;
00434 }
00435
00436 for (i = -radius; i <= radius; ++i) {
00437 cxdouble x2 = i * i;
00438 cxdouble y = exp(-x2 / (2. * w2));
00439
00440 cpl_matrix_set(kernel, 0, i + radius, y);
00441 }
00442
00443
00444 fimage = cpl_image_new(cpl_image_get_size_x(image),
00445 cpl_image_get_size_y(image),
00446 cpl_image_get_type(image));
00447
00448 if (fimage == NULL) {
00449 cpl_matrix_delete(kernel);
00450 return NULL;
00451 }
00452
00453 cpl_image_filter(fimage, image, kernel, CPL_FILTER_LINEAR,
00454 CPL_BORDER_FILTER);
00455 cpl_matrix_delete(kernel);
00456
00457 return fimage;
00458
00459 }
00460
00461
00462 inline static cpl_image*
00463 _giraffe_filter_sobel(const cpl_image* image, cxbool vertical)
00464 {
00465 cpl_matrix* kernel = cpl_matrix_new(3, 3);
00466
00467 cpl_image* fimage = NULL;
00468
00469
00470 if (kernel == NULL) {
00471 return NULL;
00472 }
00473
00474 if (vertical) {
00475
00476 #if 1
00477 cpl_matrix_set(kernel, 0, 0, -1);
00478 cpl_matrix_set(kernel, 1, 0, -2);
00479 cpl_matrix_set(kernel, 2, 0, -1);
00480
00481 cpl_matrix_set(kernel, 0, 2, 1);
00482 cpl_matrix_set(kernel, 1, 2, 2);
00483 cpl_matrix_set(kernel, 2, 2, 1);
00484 #else
00485 cpl_matrix_set(kernel, 0, 0, 0);
00486 cpl_matrix_set(kernel, 1, 0, -0.5);
00487 cpl_matrix_set(kernel, 2, 0, 0);
00488
00489 cpl_matrix_set(kernel, 0, 2, 0);
00490 cpl_matrix_set(kernel, 1, 2, 0.5);
00491 cpl_matrix_set(kernel, 2, 2, 0);
00492 #endif
00493
00494 }
00495 else {
00496 cpl_matrix_set(kernel, 0, 0, 1);
00497 cpl_matrix_set(kernel, 0, 1, 2);
00498 cpl_matrix_set(kernel, 0, 2, 1);
00499
00500 cpl_matrix_set(kernel, 2, 0, -1);
00501 cpl_matrix_set(kernel, 2, 1, -2);
00502 cpl_matrix_set(kernel, 2, 2, -1);
00503 }
00504
00505
00506 fimage = cpl_image_new(cpl_image_get_size_x(image),
00507 cpl_image_get_size_y(image),
00508 cpl_image_get_type(image));
00509
00510 if (fimage == NULL) {
00511 cpl_matrix_delete(kernel);
00512 return NULL;
00513 }
00514
00515 cpl_image_filter(fimage, image, kernel, CPL_FILTER_LINEAR,
00516 CPL_BORDER_FILTER);
00517 cpl_matrix_delete(kernel);
00518
00519 return fimage;
00520
00521 }
00522
00523
00524 inline static cxint
00525 _giraffe_build_edge_mask(cpl_image* raw, cpl_image* bpixel, cxint nspectra,
00526 cxdouble noise, GiMaskParameters* config,
00527 cxint* ndetect, cpl_matrix* mxok, cpl_matrix* myup,
00528 cpl_matrix* mylo)
00529 {
00530
00531 const cxint margin = 5;
00532
00533 cxint m = 0;
00534 cxint itrace = 0;
00535 cxint ispectra = 0;
00536 cxint mmax = 0;
00537 cxint smax = 0;
00538 cxint naccepted = 0;
00539 cxint nrows = cpl_image_get_size_y(raw);
00540 cxint ncols = cpl_image_get_size_x(raw);
00541
00542 cxint* flags = NULL;
00543
00544 cxdouble* buffer = NULL;
00545
00546 cpl_mask* kernel = NULL;
00547
00548 cpl_image* fraw = NULL;
00549 cpl_image* sraw = NULL;
00550 cpl_image* vertical1 = NULL;
00551 cpl_image* vertical2 = NULL;
00552 cpl_image* center = NULL;
00553
00554
00555 *ndetect = 0;
00556
00557
00558
00559
00560
00561
00562
00563 kernel = cpl_mask_new(1, 15);
00564
00565 if (kernel != NULL) {
00566
00567 cpl_mask_not(kernel);
00568
00569 fraw = cpl_image_new(ncols, nrows, cpl_image_get_type(raw));
00570
00571 if (fraw == NULL) {
00572 cpl_mask_delete(kernel);
00573 kernel = NULL;
00574
00575 return -3;
00576 }
00577
00578 cpl_image_filter_mask(fraw, raw, kernel, CPL_FILTER_MEDIAN,
00579 CPL_BORDER_FILTER);
00580
00581 }
00582
00583 cpl_mask_delete(kernel);
00584 kernel = NULL;
00585
00586
00587 sraw = _giraffe_filter_gauss1d(fraw, 6, 1.);
00588
00589 if (sraw == NULL) {
00590
00591 cpl_image_delete(fraw);
00592 fraw = NULL;
00593
00594 return -3;
00595
00596 }
00597
00598 vertical1 = _giraffe_filter_sobel(sraw, TRUE);
00599 vertical2 = _giraffe_filter_sobel(vertical1, TRUE);
00600
00601 cpl_image_save(sraw, "master_flat_smooth.fits", -32, 0, CPL_IO_DEFAULT);
00602 cpl_image_save(vertical1, "vertical.fits", -32, 0, CPL_IO_DEFAULT);
00603 cpl_image_save(vertical2, "vertical2.fits", -32, 0, CPL_IO_DEFAULT);
00604
00605
00606
00607
00608
00609
00610 center = cpl_image_new(ncols, nrows, CPL_TYPE_INT);
00611
00612 flags = cx_calloc(ncols, sizeof(cxint));
00613 buffer = cx_calloc(ncols, sizeof(cxdouble));
00614
00615 if ((center == NULL) || (flags ==NULL) || (buffer == NULL)) {
00616
00617 cx_free(buffer);
00618 buffer = NULL;
00619
00620 cx_free(flags);
00621 flags = NULL;
00622
00623 cpl_image_delete(center);
00624 center = NULL;
00625
00626 cpl_image_delete(vertical2);
00627 vertical2 = NULL;
00628
00629 cpl_image_delete(vertical1);
00630 vertical1 = NULL;
00631
00632 cpl_image_delete(sraw);
00633 sraw = NULL;
00634
00635 cpl_image_delete(fraw);
00636 fraw = NULL;
00637
00638 return -3;
00639
00640 }
00641
00642
00643 for (m = 0; m < nrows; ++m) {
00644
00645 register cxint irow = m * ncols;
00646 register cxint n = 0;
00647
00648 cxint scount = 0;
00649 cxint iteration = 0;
00650
00651 cxint* _center = cpl_image_get_data_int(center) + irow;
00652
00653 const cxdouble* _vt1 = cpl_image_get_data_double_const(vertical1) +
00654 irow;
00655 const cxdouble* _vt2 = cpl_image_get_data_double_const(vertical2) +
00656 irow;
00657 const cxdouble* _fraw = cpl_image_get_data_double_const(fraw) +
00658 irow;
00659
00660
00661 memset(buffer, 0, ncols * sizeof(cxdouble));
00662 memset(flags, 0, ncols * sizeof(cxint));
00663
00664 #if 1
00665 for (n = 0; n < ncols; ++n) {
00666
00667
00668
00669
00670
00671
00672
00673 if (_vt2[n] <= 0.) {
00674 buffer[n] = _vt1[n];
00675 if ((n - 1 >= 0) && (_vt2[n - 1] > 0.)) {
00676 buffer[n - 1] = _vt1[n - 1];
00677 }
00678 if ((n + 1 < ncols) && (_vt2[n + 1] > 0.)) {
00679 buffer[n + 1] = _vt1[n + 1];
00680 }
00681 }
00682 }
00683 #endif
00684
00685 while (iteration < ncols) {
00686
00687 cxint pos = -1;
00688
00689 cxdouble dx = 3. * 2. * noise;
00690
00691
00692 for (n = 0; n < ncols; ++n) {
00693
00694 if (!flags[n] && (buffer[n] > dx)) {
00695 dx = buffer[n];
00696 pos = n;
00697 }
00698
00699 }
00700
00701
00702 if (pos >= 0) {
00703
00704 register cxint k = 0;
00705
00706 cxint start = pos;
00707 cxint end = pos;
00708 cxint width = 0;
00709
00710 cxdouble sigma = 0.;
00711 cxdouble signal = 0.;
00712
00713
00714 flags[pos] = 1;
00715
00716 k = pos - 1;
00717 while ((k >= 0) && (buffer[k] > 0.)) {
00718 flags[k] = 1;
00719 start = k;
00720 --k;
00721 }
00722
00723 k = pos + 1;
00724 while ((k < ncols) && (buffer[k] > 0.)) {
00725 flags[k] = 1;
00726 ++k;
00727 }
00728 pos = k - 1;
00729
00730 while ((k < ncols) && (buffer[k] < 0.)) {
00731 flags[k] = 1;
00732 end = k;
00733 ++k;
00734 }
00735 width = end - start + 1;
00736
00737
00738
00739
00740
00741
00742
00743 signal = (_fraw[pos] > 0.) ? _fraw[pos] : 0.;
00744 sigma = sqrt((noise * noise + signal) / config->xbin);
00745
00746 if ((signal / sigma > 10.) && (width > 1)) {
00747
00748 start = (start == pos) ? start - 1 : start;
00749 end = (end == pos) ? end + 1 : end;
00750
00751 _center[pos] += 1;
00752 _center[start] += -1;
00753 _center[end] += -2;
00754
00755 }
00756
00757 }
00758
00759 ++iteration;
00760
00761 }
00762
00763 for (n = 0; n < ncols; ++n) {
00764
00765 if (_center[n] == 1) {
00766 ++scount;
00767 }
00768
00769 }
00770
00771 if (scount >= smax) {
00772 smax = scount;
00773 mmax = m;
00774 }
00775
00776 }
00777
00778 cx_free(buffer);
00779 buffer = NULL;
00780
00781 cx_free(flags);
00782 flags = NULL;
00783
00784
00785
00786
00787 cx_print("scount: %d (%d) at %d\n", smax, nspectra, mmax);
00788
00789
00790
00791
00792
00793
00794
00795 const cxint limit = 0.85 * nrows;
00796
00797
00798
00799
00800 const cxdouble hwf = sqrt(2. * log(2.));
00801
00802 cxint* xtrace = cx_calloc(nrows, sizeof(cxint));
00803 cxint* ytrace = cx_calloc(nrows, sizeof(cxint));
00804
00805 cpl_image* mask = cpl_image_new(ncols, nrows, CPL_TYPE_INT);
00806
00807 for (m = 0; m < ncols; ++m) {
00808
00809 const cxint* _center = cpl_image_get_data_int(center);
00810 const cxint* _reference = _center + mmax * ncols;
00811
00812 cxbool out_of_bounds = FALSE;
00813
00814 cxint connected = 0;
00815
00816
00817 if (_reference[m] == 1) {
00818
00819 register cxint j = mmax;
00820 register cxint pos = m;
00821
00822
00823 ++itrace;
00824
00825 xtrace[connected] = pos;
00826 ytrace[connected] = j;
00827
00828 j = mmax + 1;
00829
00830 while (j < nrows) {
00831
00832 register cxint k = 0;
00833 register cxint l = j * ncols;
00834 register cxint kmin = (pos - 1 >= 0) ? pos - 1 : 0;
00835 register cxint kmax = (pos + 1 < ncols) ? pos + 1 : ncols - 1;
00836
00837 for (k = kmin; k <= kmax; ++k) {
00838
00839 if (_center[l + k] == 1) {
00840 pos = k;
00841 if ((pos <= margin) || (pos >= ncols - margin)) {
00842 out_of_bounds = TRUE;
00843 }
00844 else {
00845 ++connected;
00846 xtrace[connected] = k;
00847 ytrace[connected] = j;
00848 }
00849 break;
00850 }
00851
00852 }
00853
00854 ++j;
00855
00856 }
00857
00858
00859 j = mmax - 1;
00860 pos = m;
00861
00862 while (j >= 0) {
00863
00864 register cxint k = 0;
00865 register cxint l = j * ncols;
00866 register cxint kmin = (pos - 1 >= 0) ? pos - 1 : 0;
00867 register cxint kmax = (pos + 1 < ncols) ? pos + 1 : ncols - 1;
00868
00869 for (k = kmin; k <= kmax; ++k) {
00870
00871 if (_center[l + k] == 1) {
00872 pos = k;
00873 if ((pos <= margin) || (pos >= ncols - margin)) {
00874 out_of_bounds = TRUE;
00875 }
00876 else {
00877 ++connected;
00878 xtrace[connected] = k;
00879 ytrace[connected] = j;
00880 }
00881 break;
00882 }
00883
00884 }
00885
00886 --j;
00887
00888 }
00889
00890
00891 if ((connected < limit) || (out_of_bounds == TRUE)) {
00892
00893 memset(xtrace, 0, nrows * sizeof(cxint));
00894 memset(ytrace, 0, nrows * sizeof(cxint));
00895
00896 if (out_of_bounds == TRUE) {
00897 cx_print("discarded candidate %d, going out of detector "
00898 "boundaries.\n", itrace);
00899
00900 }
00901 else {
00902 cx_print("discarded candidate %d, not enough connected "
00903 "centers (%d, required: %d)\n", itrace, connected,
00904 limit);
00905 }
00906
00907 }
00908 else {
00909
00910 cxint* _mask = cpl_image_get_data_int(mask);
00911
00912 for (j = 0; j < connected; ++j) {
00913
00914 register cxint x = xtrace[j];
00915 register cxint y = ytrace[j] * ncols;
00916 register cxint ix = x;
00917
00918 _mask[y + x] = 1;
00919
00920 while ((_center[y + ix] != -1) && (ix > 0)) {
00921 --ix;
00922 }
00923 _mask[y + ix] = -1;
00924
00925 ix = x;
00926 while ((_center[y + ix] != -2) && (ix < ncols - 1)) {
00927 ++ix;
00928 }
00929 _mask[y + ix] += -2;
00930
00931 }
00932
00933 ++ispectra;
00934
00935 }
00936
00937 }
00938
00939 }
00940
00941 cx_print("scount: %d (expected: %d)\n", ispectra, nspectra);
00942
00943 cx_free(ytrace);
00944 ytrace = NULL;
00945
00946 cx_free(xtrace);
00947 xtrace = NULL;
00948
00949 for (m = 0; m < nrows; ++m) {
00950
00951 register cxint j = 0;
00952 register cxint ns = 0;
00953
00954 const cxint* _mask = cpl_image_get_data_int(mask) + m * ncols;
00955 const cxint* _center = cpl_image_get_data_int(center) + m * ncols;
00956
00957
00958 for (j = 0; j < ncols; ++j) {
00959
00960 if (_mask[j] == 1) {
00961
00962 register cxint x = j;
00963 register cxint ix = x;
00964
00965
00966 while ((_center[ix] != -1) && (ix > 0)) {
00967 --ix;
00968 }
00969 cpl_matrix_set(mylo, naccepted, ns, x - hwf * fabs(x - ix));
00970
00971 ix = x;
00972 while ((_center[ix] != -2) && (ix < ncols - 1)) {
00973 ++ix;
00974 }
00975 cpl_matrix_set(myup, naccepted, ns, x + hwf * fabs(ix - x));
00976
00977 ++ns;
00978 }
00979
00980 }
00981
00982 if (ns == ispectra) {
00983 cpl_matrix_set(mxok, naccepted, 0, m);
00984 ++naccepted;
00985 }
00986
00987 }
00988
00989 *ndetect = ispectra;
00990
00991
00992 cpl_image_save(center, "center.fits", -32, 0, CPL_IO_DEFAULT);
00993 cpl_image_save(mask, "mask.fits", -32, 0, CPL_IO_DEFAULT);
00994
00995 cpl_image_delete(mask);
00996 cpl_image_delete(center);
00997 cpl_image_delete(vertical2);
00998 cpl_image_delete(vertical1);
00999 cpl_image_delete(sraw);
01000 cpl_image_delete(fraw);
01001
01002 return naccepted;
01003 }
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040 inline static cxint
01041 _giraffe_build_raw_mask(cpl_image *raw, cpl_image *bpixel, cxint nspectra,
01042 cxdouble noise, GiMaskParameters *config,
01043 cxint *ndetect, cpl_matrix *mxok, cpl_matrix *myup,
01044 cpl_matrix *mylo)
01045 {
01046
01047 register cxint x = 0;
01048 register cxint y = 0;
01049 register cxint xretry = 0;
01050 register cxint xok = 0;
01051
01052 cxint ny = 0;
01053 cxint nrows = 0;
01054 cxint ncols = 0;
01055 cxint *yabove = NULL;
01056 cxint *ybelow = NULL;
01057 cxint *good_pixels = NULL;
01058 cxint ywidth = config->ywidth > 1 ? config->ywidth : 2;
01059 cxint ckwidth = config->ckdata.width;
01060 cxint ckheight = config->ckdata.height;
01061 cxint ckcount = config->ckdata.count;
01062
01063
01064 cxdouble* pixels = NULL;
01065
01066 cpl_mask* med = NULL;
01067
01068 cpl_image* img = raw;
01069
01070
01071 med = cpl_mask_new(1, 15);
01072
01073 if (med != NULL) {
01074
01075 cpl_mask_not(med);
01076
01077 img = cpl_image_new(cpl_image_get_size_x(raw),
01078 cpl_image_get_size_y(raw),
01079 cpl_image_get_type(raw));
01080
01081 cpl_image_filter_mask(img, raw, med, CPL_FILTER_MEDIAN,
01082 CPL_BORDER_FILTER);
01083
01084 }
01085
01086 cpl_mask_delete(med);
01087 med = NULL;
01088
01089 *ndetect = 0;
01090
01091 GIDEBUG(gi_message("noise = %g start = %d tries = %d xbin = %d "
01092 "ywidth = %d", noise, config->start, config->retry,
01093 config->xbin, ywidth));
01094
01095 pixels = cpl_image_get_data_double(img);
01096
01097 nrows = cpl_image_get_size_y(img);
01098 ncols = cpl_image_get_size_x(img);
01099
01100
01101 if (config->xbin > 1) {
01102
01103 cxint nx = nrows;
01104
01105 cxdouble* _pixels = NULL;
01106
01107
01108 nrows = (cxint) ceil(nrows / config->xbin);
01109 config->start = (cxint) ceil(config->start / config->xbin);
01110
01111 _pixels = cx_calloc(ncols * nrows, sizeof(cxdouble));
01112
01113 for (y = 0; y < ncols; ++y) {
01114
01115 for (x = 0; x < nrows; ++x) {
01116
01117 register cxint xx = 0;
01118 register cxint zx = x * ncols;
01119 register cxint xr = x * config->xbin;
01120 register cxint zr = xr * ncols;
01121
01122
01123 _pixels[zx + y] = 0.;
01124
01125 for (xx = 0; xx < config->xbin && xr < nx; ++xx) {
01126 _pixels[zx + y] += pixels[zr + y];
01127 }
01128
01129 _pixels[zx + y] /= config->xbin;
01130
01131 }
01132
01133 }
01134
01135 pixels = _pixels;
01136
01137 }
01138
01139 good_pixels = cx_calloc(nrows * ncols, sizeof(cxint));
01140
01141 switch (config->method) {
01142
01143 case GILOCALIZE_THRESHOLD_LOCAL:
01144 {
01145
01146 cxint ywidth2 = ywidth / 2;
01147 cxint sz = 2 * ywidth2 + 1;
01148
01149 cpl_vector* ymins = cpl_vector_new(sz);
01150
01151
01152
01153
01154
01155
01156
01157
01158 for (x = 0; x < nrows; x++) {
01159
01160 cpl_vector_fill(ymins, 0.);
01161
01162 for (y = 0; y < ncols; y++) {
01163
01164 register cxint k = 0;
01165 register cxint kk = 0;
01166
01167 cxdouble value = 0.;
01168 cxdouble bkg = 0.;
01169 cxdouble threshold = 0.;
01170
01171
01172 for (kk = 0, k = -ywidth2; k <= ywidth2; k++) {
01173
01174 register cxint ky = y + k;
01175
01176 if (ky < 0 || ky >= ncols) {
01177 continue;
01178 }
01179
01180 cpl_vector_set(ymins, kk, pixels[x * ncols + ky]);
01181 ++kk;
01182 }
01183
01184 if (kk == 0) {
01185 continue;
01186 }
01187
01188 if (config->threshold > 0.) {
01189
01190 const cxint count = 2;
01191
01192 cxint i = 0;
01193
01194
01195
01196
01197
01198
01199
01200
01201 giraffe_array_sort(cpl_vector_get_data(ymins), kk);
01202
01203 bkg = 0.;
01204
01205 for (i = 0; i < count; i++) {
01206 bkg += fabs(cpl_vector_get(ymins, i));
01207 }
01208 bkg /= (cxdouble)count;
01209
01210 threshold = sqrt((2. * noise * noise +
01211 fabs(pixels[x * ncols + y]) + bkg / count) / config->xbin);
01212
01213 }
01214 else {
01215
01216 register cxint i;
01217 register cxdouble mean = 0.;
01218
01219
01220 for (i = 0; i < kk; i++) {
01221 mean += cpl_vector_get(ymins, i);
01222 }
01223 mean /= kk;
01224
01225 giraffe_array_sort(cpl_vector_get_data(ymins), kk);
01226
01227 bkg = (cpl_vector_get(ymins, 0) +
01228 cpl_vector_get(ymins, 1)) / 2.0;
01229 threshold = mean - bkg;
01230
01231 }
01232
01233
01234
01235
01236
01237
01238 value = pixels[x * ncols + y] - bkg;
01239
01240 if (value < 0.) {
01241 continue;
01242 }
01243
01244 if (value > fabs(config->threshold) * threshold) {
01245 good_pixels[x * ncols + y] = 1;
01246 }
01247 }
01248 }
01249
01250 cpl_vector_delete(ymins);
01251 ymins = NULL;
01252
01253 break;
01254
01255 }
01256
01257 case GILOCALIZE_THRESHOLD_ROW:
01258 {
01259
01260 cpl_image* snr = cpl_image_abs_create(raw);
01261
01262 cxint sx = cpl_image_get_size_x(snr);
01263
01264
01265 cpl_image_power(snr, 0.5);
01266
01267 for (x = 0; x < nrows; ++x) {
01268
01269 const cxdouble* _snr = cpl_image_get_data_double_const(snr);
01270
01271 cxdouble avsnr = giraffe_array_median(_snr + x * sx, sx);
01272
01273
01274 for (y = 0; y < ncols; ++y) {
01275
01276 if (pixels[x * ncols + y] <= 0.) {
01277 continue;
01278 }
01279
01280 if (_snr[x * ncols + y] > avsnr * fabs(config->threshold)) {
01281 good_pixels[x * ncols + y] = 1;
01282 }
01283
01284 }
01285
01286 }
01287
01288 cpl_image_delete(snr);
01289 snr = NULL;
01290
01291 break;
01292
01293 }
01294
01295 default:
01296 {
01297
01298 cxdouble threshold = 0.;
01299
01300
01301
01302
01303
01304
01305 if (config->threshold > 0.) {
01306 threshold = config->threshold * noise;
01307 }
01308 else {
01309
01310 cxdouble mean = cpl_image_get_mean(raw);
01311
01312 threshold = -config->threshold * mean *
01313 (nspectra * config->wavg / ncols);
01314
01315 }
01316
01317 for (x = 0; x < nrows; x++) {
01318
01319 for (y = 0; y < ncols; y++) {
01320
01321 if (pixels[x * ncols + y] > threshold) {
01322 good_pixels[x * ncols + y] = 1;
01323 }
01324
01325 }
01326
01327 }
01328
01329 break;
01330
01331 }
01332
01333 }
01334
01335 GIDEBUG(cxint *data = cx_calloc(nrows * ncols, sizeof(cxint));
01336 memcpy(data, good_pixels, nrows * ncols * sizeof(cxint));
01337 cpl_image *gp = cpl_image_wrap_int(ncols, nrows, data);
01338 cpl_image_save(gp, "locmask.fits", 32, NULL, CPL_IO_DEFAULT);
01339 cpl_image_unwrap(gp);
01340 cx_free(data));
01341
01342
01343
01344
01345
01346
01347 yabove = cx_calloc(nspectra + 1, sizeof(cxint));
01348 ybelow = cx_calloc(nspectra + 1, sizeof(cxint));
01349
01350
01351
01352
01353
01354
01355 ny = ncols - 1;
01356
01357 xretry = 0;
01358 xok = 0;
01359
01360 for (x = config->start; (x >= 0) && (xretry <= config->retry); x--) {
01361
01362 register cxint zx = x * ncols;
01363 register cxint nborders = 0;
01364 register cxint nbelow = 0;
01365 register cxint nabove = 0;
01366 register cxint in_spectrum = 0;
01367
01368
01369 for (y = 1; y < ny; y++) {
01370
01371 register cxint tmp = 2 * good_pixels[zx + y];
01372
01373
01374
01375
01376
01377 nborders = CX_MAX(CX_MAX(nborders, nbelow), nabove);
01378
01379 if (nborders > nspectra) {
01380 break;
01381 }
01382
01383
01384
01385
01386
01387
01388
01389 if (good_pixels[zx + y + 1]) {
01390
01391
01392
01393
01394
01395
01396 if ((tmp - good_pixels[zx + y - 1]) == 2) {
01397
01398
01399
01400
01401
01402
01403 if (!in_spectrum) {
01404
01405
01406
01407
01408
01409
01410 ybelow[nbelow++] = y;
01411 in_spectrum = 1;
01412
01413 }
01414
01415 }
01416
01417 }
01418
01419 if (good_pixels[zx + y - 1]) {
01420
01421
01422
01423
01424
01425
01426 if ((tmp - good_pixels[zx + y + 1]) == 2) {
01427
01428
01429
01430
01431
01432
01433 if (in_spectrum) {
01434
01435
01436
01437
01438
01439
01440 yabove[nabove++] = y;
01441 in_spectrum = 0;
01442
01443 }
01444
01445 }
01446
01447 }
01448
01449
01450
01451 if (tmp &&
01452 !good_pixels[zx + y - 1] && !good_pixels[zx + y + 1]) {
01453
01454 if (_giraffe_validate_pixel(good_pixels, ncols, nrows, y, x,
01455 ckwidth, ckheight, ckcount)) {
01456
01457 yabove[nabove++] = y;
01458 ybelow[nbelow++] = y;
01459 }
01460
01461 }
01462
01463 }
01464
01465 if (in_spectrum) {
01466 nborders--;
01467 nbelow--;
01468 in_spectrum = 0;
01469 }
01470
01471 *ndetect = nborders;
01472
01473 if (!in_spectrum && (nbelow == nspectra) && (nbelow == nabove)) {
01474
01475
01476
01477
01478
01479
01480
01481
01482 for (y = 0; y < nspectra; y++) {
01483 cpl_matrix_set(mylo, xok, y, (cxdouble) ybelow[y]);
01484 cpl_matrix_set(myup, xok, y, (cxdouble) yabove[y]);
01485 cpl_matrix_set(mxok, xok, 0, (config->xbin > 1) ?
01486 (cxdouble) (x + 0.5) * config->xbin :
01487 (cxdouble) x);
01488 }
01489 xok++;
01490 xretry = 0;
01491 }
01492 else if (xretry++ < config->retry) {
01493
01494
01495
01496
01497
01498
01499 continue;
01500 }
01501 else {
01502
01503
01504
01505
01506
01507 break;
01508 }
01509 }
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520 xretry = 0;
01521
01522 for (x = config->start + 1; (x < nrows) &&
01523 (xretry <= config->retry); x++) {
01524
01525 register cxint zx = x * ncols;
01526 register cxint nborders = 0;
01527 register cxint nbelow = 0;
01528 register cxint nabove = 0;
01529 register cxint in_spectrum = 0;
01530
01531
01532 for (y = 1; y < ny; y++) {
01533
01534 register cxint tmp = 2 * good_pixels[zx + y];
01535
01536 nborders = CX_MAX(CX_MAX(nborders, nbelow), nabove);
01537
01538 if (nborders > nspectra) {
01539 break;
01540 }
01541
01542 if (good_pixels[zx + y + 1]) {
01543 if ((tmp - good_pixels[zx + y - 1]) == 2) {
01544 if (!in_spectrum) {
01545 ybelow[nbelow++] = y;
01546 in_spectrum = 1;
01547 }
01548 }
01549 }
01550
01551 if (good_pixels[zx + y - 1]) {
01552 if ((tmp - good_pixels[zx + y + 1]) == 2) {
01553 if (in_spectrum) {
01554 yabove[nabove++] = y;
01555 in_spectrum = 0;
01556 }
01557 }
01558 }
01559
01560
01561
01562 if (tmp &&
01563 !good_pixels[zx + y - 1] && !good_pixels[zx + y + 1]) {
01564
01565 if (_giraffe_validate_pixel(good_pixels, ncols, nrows, y, x,
01566 ckwidth, ckheight, ckcount)) {
01567
01568 yabove[nabove++] = y;
01569 ybelow[nbelow++] = y;
01570 }
01571
01572 }
01573
01574 }
01575
01576 if (in_spectrum) {
01577 nborders--;
01578 nbelow--;
01579 in_spectrum = 0;
01580 }
01581
01582 *ndetect = nborders;
01583
01584 if (!in_spectrum && (nbelow == nspectra) && (nbelow == nabove)) {
01585
01586 for (y = 0; y < nspectra; y++) {
01587 cpl_matrix_set(mylo, xok, y, (cxdouble) ybelow[y]);
01588 cpl_matrix_set(myup, xok, y, (cxdouble) yabove[y]);
01589 cpl_matrix_set(mxok, xok, 0, (config->xbin > 1) ?
01590 (cxdouble) (x + 0.5) * config->xbin :
01591 (cxdouble) x);
01592 }
01593 xok++;
01594 xretry = 0;
01595 }
01596 else if (xretry++ < config->retry) {
01597 continue;
01598 }
01599 else {
01600 break;
01601 }
01602
01603 }
01604
01605 cx_free(ybelow);
01606 cx_free(yabove);
01607 cx_free(good_pixels);
01608
01609 if (pixels != cpl_image_get_data_double(img)) {
01610 cx_free(pixels);
01611 pixels = NULL;
01612 }
01613
01614 if (img != raw) {
01615 cpl_image_delete(img);
01616 img = NULL;
01617 }
01618
01619 if (xok == 0) {
01620 if (*ndetect < nspectra) {
01621 return -1;
01622 }
01623 else if (*ndetect > nspectra) {
01624 return -1;
01625 }
01626 else {
01627 return -2;
01628 }
01629 }
01630 else {
01631 *ndetect = nspectra;
01632 }
01633
01634 return xok;
01635
01636 }
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664 inline static void
01665 _giraffe_fit_raw_mask(cpl_matrix *mxok, cpl_matrix *myup, cpl_matrix *mylo,
01666 cpl_table *fibers, GiMaskParameters *config,
01667 GiMaskPosition *position)
01668 {
01669
01670 register cxint nn, x, nspectra;
01671 register cxint nx = cpl_matrix_get_nrow(position->my);
01672 register cxint ns = cpl_table_get_nrow(fibers);
01673
01674 cpl_matrix *mxraw;
01675 cpl_matrix *base;
01676 cpl_matrix *mcoeff;
01677
01678
01679
01680 mxraw = cpl_matrix_new(nx, 1);
01681 mcoeff = cpl_matrix_new(config->ydeg + 1, 1);
01682
01683
01684
01685
01686
01687
01688 for (x = 0; x < nx; x++) {
01689 cpl_matrix_set(mxraw, x, 0, x);
01690 }
01691
01692
01693
01694
01695
01696 base = giraffe_chebyshev_base1d(0., nx, config->ydeg + 1, mxraw);
01697 cpl_matrix_delete(mxraw);
01698
01699 nspectra = 0;
01700 for (nn = 0; nn < ns; nn++) {
01701 cpl_matrix *ylofit = NULL;
01702 cpl_matrix *yupfit = NULL;
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715 ylofit = _giraffe_fit_border(mylo, base, mxok, nspectra,
01716 config->sigma, config->niter,
01717 config->mfrac, mcoeff);
01718 if (ylofit == NULL) {
01719 cpl_msg_warning(_task, "Could not compute low border for "
01720 "spectrum %d", nn);
01721 nspectra++;
01722 continue;
01723 }
01724
01725
01726 yupfit = _giraffe_fit_border(myup, base, mxok, nspectra,
01727 config->sigma, config->niter,
01728 config->mfrac, mcoeff);
01729 if (yupfit == NULL) {
01730 cpl_msg_warning(_task, "Could not compute up border for "
01731 "spectrum %d", nn);
01732 nspectra++;
01733 continue;
01734 }
01735
01736
01737
01738
01739
01740
01741
01742 for (x = 0; x < nx; x++) {
01743
01744 cpl_matrix_set(position->my, x, nn, 0.5 *
01745 (cpl_matrix_get(yupfit, x, 0) +
01746 cpl_matrix_get(ylofit, x, 0)));
01747
01748 cpl_matrix_set(position->my, x, nn, 0.5 *
01749 (cpl_matrix_get(yupfit, x, 0) -
01750 cpl_matrix_get(ylofit, x, 0)) + config->ewid);
01751
01752 }
01753 cpl_matrix_delete(ylofit);
01754 cpl_matrix_delete(yupfit);
01755 nspectra++;
01756
01757 }
01758
01759 cpl_msg_info(_task, "%03d spectrum positions fitted", nspectra);
01760
01761 cpl_matrix_delete(base);
01762 cpl_matrix_delete(mcoeff);
01763
01764 if (nspectra == 0) {
01765 cpl_msg_warning(_task, "could not fit any spectra, check number "
01766 "of good wavelength bins");
01767 return;
01768 }
01769
01770 return;
01771
01772 }
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809 inline static void
01810 _giraffe_fit_raw_centroid(cpl_image* mz, cpl_matrix* mxok, cpl_matrix* myup,
01811 cpl_matrix* mylo, cpl_table* fibers,
01812 GiMaskParameters* config, GiMaskPosition* position,
01813 GiMaskPosition* coeffs)
01814 {
01815
01816 const cxchar* const fctid = "_giraffe_fit_raw_centroid";
01817
01818 register cxint nn = 0;
01819 register cxint x = 0;
01820 register cxint y = 0;
01821 register cxint nspectra = 0;
01822 register cxint nx = cpl_image_get_size_y(mz);
01823 register cxint ny = cpl_image_get_size_x(mz);
01824 register cxint ns = cpl_table_get_nrow(fibers);
01825
01826 cxint yorder = config->ydeg + 1;
01827 cxint worder = config->wdeg + 1;
01828
01829 cpl_matrix* mxraw = NULL;
01830 cpl_matrix* base = NULL;
01831 cpl_matrix* mycenter = NULL;
01832 cpl_matrix* mywidth = NULL;
01833 cpl_matrix* mx = NULL;
01834 cpl_matrix* my = NULL;
01835 cpl_matrix* mw = NULL;
01836 cpl_matrix* chebcoeff = NULL;
01837 cpl_matrix* mfitlocw = NULL;
01838 cpl_matrix* ycenfit = NULL;
01839 cpl_matrix* ycencoeff = NULL;
01840
01841
01842
01843 if (cpl_matrix_get_nrow(position->my) != nx ||
01844 cpl_matrix_get_ncol(position->my) != ns) {
01845 gi_error("%s: invalid size for position->my[%d,%d], expected "
01846 "[%d,%d]", fctid, cpl_matrix_get_nrow(position->my),
01847 cpl_matrix_get_ncol(position->my), nx, ns);
01848 return;
01849 }
01850
01851 if (cpl_matrix_get_nrow(position->mw) != nx ||
01852 cpl_matrix_get_ncol(position->mw) != ns) {
01853 gi_error("%s: invalid size for position->mw[%d,%d], expected "
01854 "[%d,%d]", fctid, cpl_matrix_get_nrow(position->my),
01855 cpl_matrix_get_ncol(position->my), nx, ns);
01856 return;
01857 }
01858
01859
01860
01861
01862
01863
01864 mxraw = cpl_matrix_new(nx, 1);
01865
01866 for (x = 0; x < nx; x++) {
01867 cpl_matrix_set(mxraw, x, 0, x);
01868 }
01869
01870
01871
01872
01873
01874
01875 base = giraffe_chebyshev_base1d(0., nx, yorder, mxraw);
01876 cpl_matrix_delete(mxraw);
01877
01878 mycenter = cpl_matrix_new(cpl_matrix_get_nrow(mxok), ns);
01879 mywidth = cpl_matrix_new(1, cpl_matrix_get_nrow(mxok) * ns);
01880
01881 ycencoeff = cpl_matrix_new(yorder, 1);
01882
01883 for (nn = 0; nn < ns; nn++) {
01884
01885
01886
01887
01888
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900 cxdouble* pixels = cpl_image_get_data_double(mz);
01901
01902 for (x = 0; x < cpl_matrix_get_nrow(mxok); x++) {
01903
01904 register cxint zx = (cxint) cpl_matrix_get(mxok, x, 0);
01905
01906 register cxdouble zz = 0.;
01907 register cxdouble yy = 0.;
01908
01909 cxdouble lower = cpl_matrix_get(mylo, x, nspectra);
01910 cxdouble upper = cpl_matrix_get(myup, x, nspectra);
01911
01912
01913 for (y = (cxint) lower; y <= (cxint) upper; y++) {
01914 yy += pixels[zx * ny + y] * y;
01915 zz += pixels[zx * ny + y];
01916 }
01917
01918 cpl_matrix_set(mycenter, x, nspectra, yy / zz);
01919 cpl_matrix_set(mywidth, 0, x * ns + nspectra, config->ewid +
01920 (upper - lower) / 2.0);
01921
01922 }
01923
01924
01925
01926
01927
01928 cpl_matrix_fill(ycencoeff, 0.);
01929 ycenfit = _giraffe_fit_border(mycenter, base, mxok, nspectra,
01930 config->sigma, config->niter,
01931 config->mfrac, ycencoeff);
01932 if (ycenfit == NULL) {
01933 cpl_msg_warning(_task, "Could not fit centroid for spectrum %d",
01934 nn);
01935 nspectra++;
01936 continue;
01937 }
01938
01939
01940
01941
01942
01943 for (x = 0; x < yorder; x++) {
01944 cpl_matrix_set(coeffs->my, x, nn,
01945 cpl_matrix_get(ycencoeff, x, 0));
01946 }
01947
01948
01949
01950
01951
01952
01953 for (x = 0; x < nx; x++) {
01954 cpl_matrix_set(position->my, x, nn,
01955 cpl_matrix_get(ycenfit, 0, x));
01956 }
01957
01958 cpl_matrix_delete(ycenfit);
01959 nspectra++;
01960
01961 }
01962
01963 GIDEBUG(cpl_image *lycenter = giraffe_matrix_create_image(mycenter);
01964 cpl_image_save(lycenter, "lycenter.fits", -32, NULL,
01965 CPL_IO_DEFAULT);
01966 cpl_image_delete(lycenter);
01967
01968 lycenter = giraffe_matrix_create_image(position->my);
01969 cpl_image_save(lycenter, "lycenterfit.fits", -32, NULL,
01970 CPL_IO_DEFAULT);
01971 cpl_image_delete(lycenter);
01972
01973 cpl_image *lyxok = giraffe_matrix_create_image(mxok);
01974 cpl_image_save(lyxok, "lyxok.fits", -32, NULL,
01975 CPL_IO_DEFAULT);
01976 cpl_image_delete(lyxok));
01977
01978
01979 cpl_msg_info(_task, "%03d spectrum positions fitted", nspectra);
01980
01981 cpl_matrix_delete(base);
01982 cpl_matrix_delete(mycenter);
01983 cpl_matrix_delete(ycencoeff);
01984
01985 if (nspectra == 0) {
01986 cpl_msg_warning(_task, "Could not fit any spectra, check number of "
01987 "good wavelength bins");
01988
01989 cpl_matrix_delete(mywidth);
01990 return;
01991 }
01992
01993
01994
01995
01996
01997 cpl_msg_info(_task, "2D fit (order %dx%d) of mask width", worder,
01998 worder);
01999
02000
02001
02002
02003
02004 mx = cpl_matrix_new(cpl_matrix_get_nrow(mxok) * nspectra, 1);
02005 my = cpl_matrix_new(cpl_matrix_get_nrow(mxok) * nspectra, 1);
02006 mw = cpl_matrix_new(1, cpl_matrix_get_nrow(mxok) * nspectra);
02007
02008 for (y = 0, nn = 0; nn < nspectra; nn++) {
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020 for (x = 0; x < cpl_matrix_get_nrow(mxok); x++) {
02021
02022 register cxint zx = (cxint) cpl_matrix_get(mxok, x, 0);
02023 register cxint lx = x * nspectra + y;
02024
02025
02026 cpl_matrix_set(mx, lx, 0, cpl_matrix_get(mxok, x, 0));
02027 cpl_matrix_set(my, lx, 0, cpl_matrix_get(position->my, zx, nn));
02028 cpl_matrix_set(mw, 0, lx, cpl_matrix_get(mywidth, 0, x * ns + y));
02029 }
02030 y++;
02031 }
02032
02033 base = giraffe_chebyshev_base2d(0., 0., nx, ny, worder, worder, mx, my);
02034
02035 cpl_matrix_delete(my);
02036 cpl_matrix_delete(mx);
02037
02038 chebcoeff = giraffe_matrix_leastsq(base, mw);
02039 cpl_matrix_delete(base);
02040 cpl_matrix_delete(mw);
02041
02042 cpl_matrix_delete(mywidth);
02043
02044 if (chebcoeff == NULL) {
02045 gi_warning("%s: error in giraffe_matrix_leastsq() for width 2D fit",
02046 fctid);
02047 return;
02048 }
02049
02050
02051
02052
02053
02054 for (nn = 0; nn < cpl_matrix_get_ncol(chebcoeff); nn++) {
02055 cpl_matrix_set(coeffs->mw, 0, nn, cpl_matrix_get(chebcoeff, 0, nn));
02056 }
02057
02058
02059
02060
02061
02062 mx = cpl_matrix_new(nx * nspectra, 1);
02063 my = cpl_matrix_new(nx * nspectra, 1);
02064
02065 for (y = 0, nn = 0; nn < nspectra; nn++) {
02066
02067
02068
02069
02070
02071
02072
02073
02074
02075
02076
02077 for (x = 0; x < nx; x++) {
02078
02079 register cxint lx = x * nspectra + y;
02080
02081 cpl_matrix_set(mx, lx, 0, x);
02082 cpl_matrix_set(my, lx, 0, cpl_matrix_get(position->my, x, nn));
02083
02084 }
02085 y++;
02086 }
02087
02088 cpl_matrix_set_size(chebcoeff, worder, worder);
02089
02090 mfitlocw = giraffe_chebyshev_fit2d(0., 0., nx, ny, chebcoeff, mx, my);
02091 cpl_matrix_delete(chebcoeff);
02092
02093 cpl_matrix_delete(my);
02094 cpl_matrix_delete(mx);
02095
02096 for (y = 0, nn = 0; nn < nspectra; nn++) {
02097
02098
02099
02100
02101
02102
02103
02104
02105
02106
02107
02108 for (x = 0; x < nx; x++) {
02109
02110 register cxint lx = x * nspectra + y;
02111
02112 cpl_matrix_set(position->mw, x, nn,
02113 cpl_matrix_get(mfitlocw, lx, 0));
02114
02115 }
02116 y++;
02117 }
02118
02119 cpl_matrix_delete(mfitlocw);
02120
02121 return;
02122
02123 }
02124
02125
02126
02127
02128
02129
02130
02131
02132
02133
02134
02135
02136
02137
02138
02139
02140
02141
02142
02143
02144
02145
02146
02147
02148
02149
02150
02151 inline static cxint
02152 _giraffe_localize_spectra(cpl_image *mzraw, cpl_image *bpixel,
02153 cpl_table *fibers, GiLocalizeMethod method,
02154 cxbool normalize, cxdouble noise,
02155 GiMaskParameters *config, GiMaskPosition *position,
02156 GiMaskPosition *coeffs)
02157 {
02158
02159 cxint n, nn;
02160 cxint nx, ny, nxok;
02161 cxint ndetect, nspectra;
02162 cxint x, y;
02163
02164 cxdouble uplost = 0.;
02165 cxdouble lolost = 0.;
02166 cxdouble avglost = 0.;
02167 cxdouble avgmask = 0.;
02168 cxdouble sigmask = 0.;
02169 cxdouble sigmean = 0.;
02170 cxdouble avgborders = 0.;
02171
02172 cxdouble *_mzraw;
02173
02174 cpl_matrix *mxok;
02175 cpl_matrix *myup;
02176 cpl_matrix *mylo;
02177 cpl_matrix *mwid;
02178
02179 cpl_image *mz = NULL;
02180 cpl_image *mznorm = NULL;
02181
02182
02183
02184 nx = cpl_image_get_size_y(mzraw);
02185 ny = cpl_image_get_size_x(mzraw);
02186 _mzraw = cpl_image_get_data_double(mzraw);
02187
02188
02189 if (normalize == TRUE) {
02190
02191 cxdouble zxmax = 0.0;
02192 cxdouble *_mzx = NULL;
02193 cxdouble *_mznorm = NULL;
02194
02195 cpl_image *mzx = NULL;
02196
02197
02198 cpl_msg_info(_task, "Using normalized spectra for localization");
02199
02200
02201
02202
02203
02204
02205
02206
02207 mznorm = cpl_image_new(ny, nx, CPL_TYPE_DOUBLE);
02208 _mznorm = cpl_image_get_data_double(mznorm);
02209
02210 mzx = cpl_image_new(1, nx, CPL_TYPE_DOUBLE);
02211 _mzx = cpl_image_get_data_double(mzx);
02212
02213
02214
02215
02216
02217
02218 for (x = 0 ; x < nx; x++) {
02219 for (y = 0 ; y < ny; y++) {
02220 _mzx[x] += _mzraw[x * ny + y];
02221 }
02222
02223
02224
02225
02226
02227 if (_mzx[x] > zxmax) {
02228 zxmax = _mzx[x];
02229 }
02230 }
02231
02232 GIDEBUG(cpl_image_save(mzx, "mzx.fits", -32, NULL, CPL_IO_DEFAULT));
02233
02234 for (x = 0 ; x < nx; x++) {
02235
02236 register cxdouble zxnorm = zxmax / _mzx[x];
02237
02238 for (y = 0 ; y < ny; y++) {
02239 _mznorm[x * ny + y] = _mzraw[x * ny + y] * zxnorm;
02240 }
02241
02242 }
02243
02244 cpl_image_delete(mzx);
02245 mz = mznorm;
02246 }
02247 else {
02248
02249
02250
02251
02252
02253 cpl_msg_info(_task, "Using raw spectra for localization");
02254 mz = mzraw;
02255 }
02256
02257
02258
02259
02260
02261
02262 nspectra = cpl_table_get_nrow(fibers);
02263
02264 mxok = cpl_matrix_new(nx, 1);
02265 myup = cpl_matrix_new(nx, nspectra);
02266 mylo = cpl_matrix_new(nx, nspectra);
02267
02268
02269
02270
02271
02272
02273 config->xbin = (config->xbin > 1) ? 2 * (config->xbin / 2) : 1;
02274
02275 GIDEBUG(cpl_image_save(mz, "mz.fits", -32, NULL, CPL_IO_DEFAULT));
02276
02277
02278
02279
02280
02281
02282 cpl_msg_info(_task, "Generating mask (%d spectra expected) ...",
02283 nspectra);
02284
02285
02286
02287 #if 0
02288 nxok = _giraffe_build_edge_mask(mz, bpixel, nspectra, noise, config,
02289 &ndetect, mxok, myup, mylo);
02290 #endif
02291
02292
02293
02294 nxok = _giraffe_build_raw_mask(mz, bpixel, nspectra, noise, config,
02295 &ndetect, mxok, myup, mylo);
02296
02297 if (nxok < 0) {
02298
02299 switch (nxok) {
02300 case -1:
02301 cpl_msg_warning(_task, "Invalid number of spectra detected: "
02302 "%d != %d", ndetect, nspectra);
02303 break;
02304
02305 case -2:
02306 cpl_msg_warning(_task, "No abcissa with good number "
02307 "of spectra");
02308 break;
02309
02310 default:
02311 cpl_msg_warning(_task, "Error while searching for spectra");
02312 }
02313
02314 return nxok;
02315
02316 }
02317 else {
02318 cpl_msg_info(_task, "%d spectra detected in %d wavelength bins",
02319 ndetect, nxok);
02320 }
02321
02322
02323
02324
02325
02326
02327 cpl_matrix_resize(mxok, 0, nxok - cpl_matrix_get_nrow(mxok), 0, 0);
02328 cpl_matrix_resize(myup, 0, nxok - cpl_matrix_get_nrow(myup), 0, 0);
02329 cpl_matrix_resize(mylo, 0, nxok - cpl_matrix_get_nrow(mylo), 0, 0);
02330
02331 GIDEBUG(gi_message("%s: mxok[0-%d]=[%g-%g]", __func__,
02332 cpl_matrix_get_nrow(mxok) - 1,
02333 cpl_matrix_get_min(mxok),
02334 cpl_matrix_get_max(mxok)));
02335
02336
02337 cpl_msg_info(_task, "Computing spectrum positions and widths in "
02338 "pixel range [%g,%g]", cpl_matrix_get_min(mxok),
02339 cpl_matrix_get_max(mxok));
02340
02341 if (cpl_matrix_get_nrow(mxok) <= config->ydeg) {
02342 cpl_msg_info(_task, "Not enough data points %d for %d order fit",
02343 cpl_matrix_get_nrow(mxok), config->ydeg);
02344
02345 return -1;
02346 }
02347
02348 switch (method) {
02349 case GILOCALIZE_HALF_WIDTH:
02350 cpl_msg_info(_task, "Using half-width for localization");
02351 _giraffe_fit_raw_mask(mxok, myup, mylo, fibers, config,
02352 position);
02353 break;
02354
02355 case GILOCALIZE_BARYCENTER:
02356 default:
02357 cpl_msg_info(_task, "Using barycenter for localization");
02358 _giraffe_fit_raw_centroid(mz, mxok, myup, mylo, fibers, config,
02359 position, coeffs);
02360 break;
02361 }
02362
02363 if (normalize == 1) {
02364 cpl_image_delete(mznorm);
02365 }
02366
02367
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377 mwid = cpl_matrix_new(nxok, nspectra);
02378
02379 for (n = 0, nn = 0; nn < cpl_table_get_nrow(fibers); nn++) {
02380
02381 for (x = 0; x < nxok; x++) {
02382 register cxint lx = (cxint) cpl_matrix_get(mxok, x, 0);
02383
02384 cxdouble lower = cpl_matrix_get(mylo, x, n);
02385 cxdouble upper = cpl_matrix_get(myup, x, n);
02386 cxdouble width = cpl_matrix_get(position->mw, lx, nn);
02387
02388 uplost += cpl_matrix_get(position->my, lx, nn) + width - upper;
02389 lolost += cpl_matrix_get(position->my, lx, nn) - width - lower;
02390
02391 avgborders += upper - lower;
02392 avgmask += width;
02393
02394 cpl_matrix_set(mwid, x, n, 2. * width);
02395 }
02396 n++;
02397 }
02398
02399 sigmean = cpl_matrix_get_mean(mwid);
02400 sigmask = giraffe_matrix_sigma_mean(mwid, sigmean);
02401 avglost = (lolost + uplost) / (nspectra * nxok);
02402 avgmask = 2.0 * avgmask / nspectra;
02403
02404 cpl_msg_info(_task, "Mask was computed using %d of %d wavelength bins",
02405 nxok, nx);
02406 cpl_msg_info(_task, "Average # of pixels per spectra: %.4g",
02407 avgmask);
02408 cpl_msg_info(_task, "Average # of in-borders pixels per spectra: %.4g",
02409 avgborders / nspectra);
02410 cpl_msg_info(_task, "Average lost pixels per spectra: %.4g",
02411 avglost);
02412 cpl_msg_info(_task, "Average lost pixels at upper border: %.4g",
02413 uplost / (nspectra * nxok));
02414 cpl_msg_info(_task, "Average lost pixels at lower border: %.4g",
02415 lolost / (nspectra * nxok));
02416 cpl_msg_info(_task, "Average spectrum width: %.4g +/- %.4g, "
02417 "(min, max) = (%.4g, %.4g)", sigmean, sigmask,
02418 cpl_matrix_get_min(mwid), cpl_matrix_get_max(mwid));
02419
02420 cpl_matrix_delete(mwid);
02421
02422 cpl_matrix_delete(mylo);
02423 cpl_matrix_delete(myup);
02424 cpl_matrix_delete(mxok);
02425
02426 return 0;
02427
02428 }
02429
02430
02431 inline static cxint
02432 _giraffe_finalize_fibers(cpl_table *fibers, cpl_matrix *locy, GiImage *mlocy,
02433 cxdouble maxoffset, cxdouble* maxshift)
02434 {
02435
02436 cxint i = 0;
02437 cxint j = 0;
02438 cxint nx = 0;
02439 cxint ny = 0;
02440 cxint _nx = 0;
02441 cxint _ny = 0;
02442 cxint nfibers = 0;
02443 cxint irow = 0;
02444
02445 cxdouble max_shift = 0.;
02446 cxdouble *positions = NULL;
02447
02448 cpl_image *_mlocy = NULL;
02449
02450
02451 if (fibers == NULL || locy == NULL || mlocy == NULL) {
02452 return -1;
02453 }
02454
02455 if (cpl_table_has_column(fibers, "RINDEX") == FALSE) {
02456 return -1;
02457 }
02458
02459 nx = cpl_matrix_get_ncol(locy);
02460 ny = cpl_matrix_get_nrow(locy);
02461
02462 nfibers = cpl_table_get_nrow(fibers);
02463
02464 _mlocy = giraffe_image_get(mlocy);
02465 _nx = cpl_image_get_size_x(_mlocy);
02466 _ny = cpl_image_get_size_y(_mlocy);
02467
02468 if (ny != _ny) {
02469 return -2;
02470 }
02471
02472 if (nfibers > _nx) {
02473 return -3;
02474 }
02475
02476 cpl_table_select_all(fibers);
02477
02478
02479
02480
02481
02482
02483 irow = (_ny - 1) / 2;
02484 positions = (cxdouble *)cpl_image_get_data(_mlocy) + irow * _nx;
02485
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495 for (i = 0; i < nfibers; i++) {
02496
02497 if (j < nx) {
02498
02499 cxint pos = cpl_table_get_int(fibers, "RINDEX", i, NULL) - 1;
02500
02501 cxdouble yc = cpl_matrix_get(locy, irow, j);
02502 cxdouble shift = fabs(yc - positions[pos]);
02503
02504 if (shift <= maxoffset) {
02505 cpl_table_unselect_row(fibers, i);
02506 ++j;
02507 }
02508 else {
02509 max_shift = CX_MAX(max_shift, shift);
02510 }
02511
02512 }
02513 }
02514
02515 cpl_table_erase_selected(fibers);
02516
02517 if (maxshift != NULL) {
02518 *maxshift = max_shift;
02519 }
02520
02521 return 0;
02522
02523 }
02524
02525
02554 cxint
02555 giraffe_localize_spectra(GiLocalization *result, GiImage *image,
02556 GiTable *fibers, GiLocalization *master,
02557 GiImage *badpixels, GiLocalizeConfig *config)
02558 {
02559
02560 const cxchar *fctid = "giraffe_localize_spectra";
02561
02562 cxint i;
02563 cxint status;
02564 cxint nrows;
02565 cxint nfibers;
02566 cxint nframes = 1;
02567 cxint ckwidth;
02568 cxint ckheight;
02569 cxint ckcount;
02570
02571 cxdouble mwidth;
02572 cxdouble conad = 0.;
02573 cxdouble bias_ron = 0.;
02574 cxdouble mask_sigma = 0.;
02575
02576 cx_string *pname;
02577
02578 cpl_propertylist *properties;
02579
02580 cpl_image *_image = giraffe_image_get(image);
02581 cpl_image *_bpixel = giraffe_image_get(badpixels);
02582 cpl_image *_result = NULL;
02583
02584 cpl_matrix *_my;
02585
02586 cpl_table *_fibers = NULL;
02587 cpl_table *fiber_setup = NULL;
02588 cpl_table *locc;
02589
02590 GiLocalizeMethod method;
02591
02592 GiInstrumentMode mode;
02593
02594 GiMaskParameters mask_config;
02595
02596 GiMaskPosition mask_position;
02597 GiMaskPosition mask_coeffs;
02598
02599
02600
02601
02602
02603
02604
02605 if (result == NULL || image == NULL || fibers == NULL || config == NULL) {
02606 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
02607 return 1;
02608 }
02609
02610 if (badpixels != NULL) {
02611 cpl_msg_debug(fctid,"Bad pixel correction is not available. Bad "
02612 "pixel map will be ignored.");
02613 }
02614
02615 _fibers = giraffe_table_get(fibers);
02616
02617 if (_fibers == NULL) {
02618 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
02619 return 1;
02620 }
02621 else {
02622 fiber_setup = _fibers;
02623 }
02624
02625 properties = giraffe_image_get_properties(image);
02626
02627
02628
02629
02630
02631
02632 nfibers = cpl_table_get_nrow(_fibers);
02633
02634 cpl_msg_info(fctid, "Setting number of fibers (%s) to %d",
02635 GIALIAS_NFIBERS, nfibers);
02636
02637 cpl_propertylist_update_int(properties, GIALIAS_NFIBERS, nfibers);
02638 cpl_propertylist_set_comment(properties, GIALIAS_NFIBERS,
02639 "Number of fibres");
02640
02641
02642 if (!cpl_propertylist_has(properties, GIALIAS_CONAD)) {
02643 cpl_msg_error(fctid, "Missing detector gain property (%s)! ",
02644 GIALIAS_CONAD);
02645 return 1;
02646 }
02647 else {
02648 conad = cpl_propertylist_get_double(properties, GIALIAS_CONAD);
02649 }
02650
02651
02652
02653
02654
02655
02656 if (config->ron > 0.) {
02657 cpl_msg_info(fctid, "Setting bias sigma value (%s) to %.5g",
02658 GIALIAS_BIASSIGMA, config->ron);
02659 cpl_propertylist_update_double(properties, GIALIAS_BIASSIGMA,
02660 config->ron);
02661 }
02662
02663 bias_ron = giraffe_propertylist_get_ron(properties);
02664 cpl_msg_info(fctid, "Bias sigma value: %.3g e-", bias_ron);
02665
02666
02667 if (cpl_propertylist_has(properties, GIALIAS_DATANCOM)) {
02668 nframes = cpl_propertylist_get_int(properties, GIALIAS_DATANCOM);
02669 }
02670
02671
02672 if (config->noise > 0.) {
02673 cpl_msg_info(fctid, "Noise multiplier: %.3g",
02674 config->noise);
02675 }
02676 else {
02677 cpl_msg_info(fctid, "Threshold multiplier: %.3g",
02678 fabs(config->noise));
02679 }
02680
02681
02682
02683
02684
02685
02686 nrows = cpl_image_get_size_y(_image);
02687
02688 if (config->start < 0) {
02689 config->start = nrows / 2;
02690 }
02691
02692
02693
02694
02695
02696
02697 mode = giraffe_get_mode(properties);
02698
02699 if (config->ywidth < 1) {
02700
02701 cpl_msg_info(fctid, "Configuring equilizing filter width from "
02702 "instrument mode");
02703
02704 switch (mode) {
02705 case GIMODE_MEDUSA:
02706 config->ywidth = 16;
02707 break;
02708
02709 case GIMODE_IFU:
02710 config->ywidth = 6;
02711 break;
02712
02713 case GIMODE_ARGUS:
02714 config->ywidth = 6;
02715 break;
02716
02717 default:
02718 cpl_msg_error(fctid, "Invalid instrument mode!");
02719 return 1;
02720 break;
02721 }
02722
02723
02724 if (!cpl_propertylist_has(properties, GIALIAS_SLITNAME)) {
02725 cpl_msg_error(fctid, "Property (%s) not found in raw image",
02726 GIALIAS_SLITNAME);
02727 return 1;
02728 }
02729 else {
02730 const cxchar *slit =
02731 cpl_propertylist_get_string(properties, GIALIAS_SLITNAME);
02732
02733 cpl_msg_info(fctid, "Setting equilizing filter to %d [pxl] "
02734 "for slit configuration `%s'", config->ywidth,
02735 slit);
02736 }
02737
02738 }
02739
02740
02741
02742
02743
02744
02745 switch (mode) {
02746 case GIMODE_MEDUSA:
02747 mwidth = GISPECTRUM_MWIDTH_MEDUSA;
02748
02749 ckwidth = 1;
02750 ckheight = 3;
02751 ckcount = 8;
02752
02753 break;
02754
02755 case GIMODE_IFU:
02756 mwidth = GISPECTRUM_MWIDTH_IFU;
02757
02758 ckwidth = 0;
02759 ckheight = 3;
02760 ckcount = 4;
02761
02762 break;
02763
02764 case GIMODE_ARGUS:
02765 mwidth = GISPECTRUM_MWIDTH_IFU;
02766
02767 ckwidth = 0;
02768 ckheight = 3;
02769 ckcount = 4;
02770
02771 break;
02772
02773 default:
02774 cpl_msg_error(fctid, "Invalid instrument mode!");
02775 return 1;
02776 break;
02777 }
02778
02779
02780
02781
02782
02783
02784 if (config->centroid == TRUE) {
02785 method = GILOCALIZE_BARYCENTER;
02786 }
02787 else {
02788 method = GILOCALIZE_HALF_WIDTH;
02789 }
02790
02791
02792
02793
02794
02795
02796
02797 mask_config.ywidth = config->ywidth;
02798 mask_config.method = config->threshold;
02799 mask_config.threshold = config->noise;
02800 mask_config.ydeg = config->yorder;
02801 mask_config.wdeg = config->worder;
02802 mask_config.ewid = config->ewidth;
02803 mask_config.wavg = mwidth;
02804 mask_config.ckdata.width = ckwidth;
02805 mask_config.ckdata.height = ckheight;
02806 mask_config.ckdata.count = ckcount;
02807 mask_config.sigma = config->sigma;
02808 mask_config.niter = config->iterations;
02809 mask_config.mfrac = config->fraction;
02810 mask_config.start = config->start;
02811 mask_config.retry = config->retries;
02812 mask_config.xbin = config->binsize;
02813
02814
02815
02816
02817
02818
02819
02820
02821
02822 if (config->noise > 0.) {
02823 mask_config.threshold *= sqrt(nframes * conad);
02824 }
02825
02826
02827
02828
02829
02830
02831
02832
02833
02834
02835
02836
02837 if (config->full != TRUE) {
02838
02839 cpl_msg_info(fctid, "Computing spectrum localization using SIWC "
02840 "spectra");
02841
02842 if (!master || !master->locy || !master->locy) {
02843 cpl_msg_error(fctid, "Required full master localization is "
02844 "missing!");
02845 return 1;
02846 }
02847
02848
02849
02850
02851
02852
02853
02854 cpl_table_unselect_all(_fibers);
02855 cpl_table_or_selected_int(_fibers, "RP", CPL_EQUAL_TO, -1);
02856
02857 fiber_setup = cpl_table_extract_selected(_fibers);
02858 nfibers = cpl_table_get_nrow(fiber_setup);
02859
02860 }
02861
02862
02863
02864
02865
02866
02867
02868 mask_position.type = GIMASK_FITTED_DATA;
02869 mask_position.my = cpl_matrix_new(nrows, nfibers);
02870 mask_position.mw = cpl_matrix_new(nrows, nfibers);
02871
02872 mask_coeffs.type = GIMASK_FIT_COEFFS;
02873 mask_coeffs.my = cpl_matrix_new(mask_config.ydeg + 1, nfibers);
02874 mask_coeffs.mw = cpl_matrix_new(1, (mask_config.wdeg + 1) *
02875 (mask_config.wdeg + 1));
02876
02877
02878
02879
02880
02881
02882
02883 _image = cpl_image_multiply_scalar_create(_image, nframes * conad);
02884
02885 mask_sigma = sqrt(nframes) * bias_ron;
02886
02887
02888
02889
02890
02891
02892 status = _giraffe_localize_spectra(_image, _bpixel, fiber_setup,
02893 method, config->normalize,
02894 mask_sigma,
02895 &mask_config, &mask_position,
02896 &mask_coeffs);
02897
02898 cpl_image_delete(_image);
02899 _image = NULL;
02900
02901 if (status) {
02902 result->locy = NULL;
02903 result->locw = NULL;
02904 result->locc = NULL;
02905 result->psf = NULL;
02906
02907 cpl_matrix_delete(mask_position.my);
02908 cpl_matrix_delete(mask_position.mw);
02909
02910 cpl_matrix_delete(mask_coeffs.my);
02911 cpl_matrix_delete(mask_coeffs.mw);
02912
02913 if (config->full != TRUE) {
02914 cpl_table_delete(fiber_setup);
02915 }
02916
02917 cpl_msg_error(fctid, "Spectrum localization computation failed!");
02918
02919 return 1;
02920 }
02921
02922
02923
02924
02925
02926
02927 if (config->full != TRUE) {
02928
02929
02930
02931
02932
02933
02934 cpl_table_delete(fiber_setup);
02935
02936 }
02937 else {
02938
02939 if (master != NULL && master->locy != NULL) {
02940
02941 cxint nf = cpl_table_get_nrow(_fibers);
02942
02943 cxdouble maxoffset = 0.5 * mask_config.wavg;
02944 cxdouble maxshift = 0.;
02945
02946
02947 cpl_msg_info(fctid, "Comparing detected and expected fiber "
02948 "positions.");
02949
02950 status = _giraffe_finalize_fibers(_fibers, mask_position.my,
02951 master->locy, maxoffset,
02952 &maxshift);
02953
02954 if (status != 0) {
02955
02956 if (status == -3) {
02957
02958 const cpl_image* mlocy = giraffe_image_get(master->locy);
02959 cxint _nf = cpl_image_get_size_x(mlocy);
02960
02961 cpl_msg_error(fctid, "More fibers (%d) than expected "
02962 "(%d) were found!", nf, _nf);
02963
02964 }
02965
02966 result->locy = NULL;
02967 result->locw = NULL;
02968 result->locc = NULL;
02969 result->psf = NULL;
02970
02971 cpl_matrix_delete(mask_position.my);
02972 cpl_matrix_delete(mask_position.mw);
02973
02974 cpl_matrix_delete(mask_coeffs.my);
02975 cpl_matrix_delete(mask_coeffs.mw);
02976
02977 if (config->full != TRUE) {
02978 cpl_table_delete(fiber_setup);
02979 }
02980
02981 cpl_msg_error(fctid, "Comparison of fiber positions "
02982 "failed!");
02983
02984 return 1;
02985 }
02986
02987 cx_assert(cpl_table_get_nrow(_fibers) <= nf);
02988
02989 cpl_msg_info(fctid, "%d of %d expected fibers were detected.",
02990 cpl_table_get_nrow(_fibers), nf);
02991
02992 if (cpl_table_get_nrow(_fibers) < nf) {
02993 cpl_msg_debug(fctid, "Maximum offset from the expected "
02994 "position is %.2f, maximum allowed offset is %.2f",
02995 maxshift, maxoffset);
02996 cpl_msg_warning(fctid, "%d fibers are missing!",
02997 nf - cpl_table_get_nrow(_fibers));
02998 }
02999
03000 }
03001
03002 }
03003
03004
03005
03006
03007
03008
03009
03010
03011
03012 result->locy =
03013 giraffe_image_create(CPL_TYPE_DOUBLE,
03014 cpl_matrix_get_ncol(mask_position.my),
03015 cpl_matrix_get_nrow(mask_position.my));
03016
03017 giraffe_image_copy_matrix(result->locy, mask_position.my);
03018 cpl_matrix_delete(mask_position.my);
03019
03020 giraffe_image_set_properties(result->locy, properties);
03021 properties = giraffe_image_get_properties(result->locy);
03022
03023 _result = giraffe_image_get(result->locy);
03024
03025 cpl_propertylist_set_int(properties, GIALIAS_NAXIS1,
03026 cpl_image_get_size_x(_result));
03027 cpl_propertylist_set_int(properties, GIALIAS_NAXIS2,
03028 cpl_image_get_size_y(_result));
03029 cpl_propertylist_set_int(properties, GIALIAS_BITPIX, -32);
03030 cpl_propertylist_set_double(properties, GIALIAS_BZERO, 0.);
03031 cpl_propertylist_set_double(properties, GIALIAS_BSCALE, 1.);
03032
03033 cpl_propertylist_append_int(properties, GIALIAS_LOCNX,
03034 cpl_image_get_size_y(_result));
03035 cpl_propertylist_append_int(properties, GIALIAS_LOCNS,
03036 cpl_image_get_size_x(_result));
03037
03038 if (config->centroid) {
03039 cpl_propertylist_append_string(properties, GIALIAS_LMETHOD,
03040 "BARYCENTER");
03041 }
03042 else {
03043 cpl_propertylist_append_string(properties, GIALIAS_LMETHOD,
03044 "HALF_WIDTH");
03045 }
03046
03047 if (config->normalize) {
03048 cpl_propertylist_append_int(properties, GIALIAS_LNORMALIZE,
03049 config->ywidth);
03050 }
03051 else {
03052 cpl_propertylist_append_int(properties, GIALIAS_LNORMALIZE,
03053 -config->ywidth);
03054 }
03055
03056 cpl_propertylist_append_bool(properties, GIALIAS_LFULLLOC, config->full);
03057 cpl_propertylist_append_int(properties, GIALIAS_LOCYDEG, config->yorder);
03058 cpl_propertylist_append_int(properties, GIALIAS_LOCWDEG, config->worder);
03059 cpl_propertylist_append_double(properties, GIALIAS_LEXTRAWID,
03060 config->ewidth);
03061 cpl_propertylist_append_double(properties, GIALIAS_LNOISEMULT,
03062 config->noise);
03063
03064 cpl_propertylist_append_double(properties, GIALIAS_LCLIPSIGMA,
03065 config->sigma);
03066 cpl_propertylist_append_int(properties, GIALIAS_LCLIPNITER,
03067 config->iterations);
03068 cpl_propertylist_append_double(properties, GIALIAS_LCLIPMFRAC,
03069 config->fraction);
03070
03071
03072 if (cpl_propertylist_has(properties, GIALIAS_GIRFTYPE)) {
03073 cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "LOCY");
03074 }
03075 else {
03076 cpl_propertylist_append_string(properties, GIALIAS_GIRFTYPE, "LOCY");
03077 }
03078 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE, "GIRAFFE "
03079 "localization centroid");
03080
03081
03082
03083
03084 result->locw =
03085 giraffe_image_create(CPL_TYPE_DOUBLE,
03086 cpl_matrix_get_ncol(mask_position.mw),
03087 cpl_matrix_get_nrow(mask_position.mw));
03088
03089 giraffe_image_copy_matrix(result->locw, mask_position.mw);
03090 cpl_matrix_delete(mask_position.mw);
03091
03092 giraffe_image_set_properties(result->locw, properties);
03093 properties = giraffe_image_get_properties(result->locw);
03094
03095 _result = giraffe_image_get(result->locw);
03096
03097 cpl_propertylist_set_int(properties, GIALIAS_NAXIS1,
03098 cpl_image_get_size_x(_result));
03099 cpl_propertylist_set_int(properties, GIALIAS_NAXIS2,
03100 cpl_image_get_size_y(_result));
03101
03102 if (cpl_propertylist_has(properties, GIALIAS_GIRFTYPE)) {
03103 cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE,
03104 "LOCWY");
03105 }
03106 else {
03107 cpl_propertylist_append_string(properties, GIALIAS_GIRFTYPE,
03108 "LOCWY");
03109 }
03110 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE, "GIRAFFE "
03111 "localization half-width");
03112
03113
03114
03115
03116 locc = cpl_table_new(cpl_matrix_get_ncol(mask_coeffs.my));
03117
03118 cpl_table_new_column(locc, "BUTTON", CPL_TYPE_INT);
03119 for (i = 0; i < cpl_table_get_nrow(locc); i++) {
03120 cpl_table_set_int(locc, "BUTTON", i, i);
03121 }
03122
03123 for (i = 0; i < cpl_matrix_get_nrow(mask_coeffs.my); i++) {
03124 cxchar *label = NULL;
03125
03126 cx_asprintf(&label, "YC%d", i);
03127 cpl_table_new_column(locc, label, CPL_TYPE_DOUBLE);
03128 cx_free(label);
03129 }
03130
03131
03132 result->locc = giraffe_table_create(locc, properties);
03133 cpl_table_delete(locc);
03134
03135 _my = cpl_matrix_transpose_create(mask_coeffs.my);
03136 giraffe_table_copy_matrix(result->locc, "YC0", _my);
03137 cpl_matrix_delete(_my);
03138 cpl_matrix_delete(mask_coeffs.my);
03139
03140 properties = giraffe_table_get_properties(result->locc);
03141
03142
03143
03144
03145 pname = cx_string_new();
03146
03147 for (i = 0; i < cpl_matrix_get_ncol(mask_coeffs.mw); i++) {
03148 cx_string_sprintf(pname, "%s%d", GIALIAS_LOCWIDCOEF, i);
03149 cpl_propertylist_append_double(properties, cx_string_get(pname),
03150 cpl_matrix_get(mask_coeffs.mw, 0, i));
03151 }
03152
03153 cx_string_delete(pname);
03154 cpl_matrix_delete(mask_coeffs.mw);
03155
03156 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
03157 "LOCYWCHEB");
03158 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE, "GIRAFFE "
03159 "localization fit coefficients");
03160
03161
03162
03163
03164 result->psf = NULL;
03165
03166 return 0;
03167
03168 }
03169
03170
03181 GiLocalizeConfig *
03182 giraffe_localize_config_create(cpl_parameterlist *list)
03183 {
03184
03185 const cxchar *s;
03186 cpl_parameter *p;
03187
03188 GiLocalizeConfig *config = NULL;
03189
03190
03191 if (list == NULL) {
03192 return NULL;
03193 }
03194
03195 config = cx_calloc(1, sizeof *config);
03196
03197
03198
03199
03200
03201
03202 config->full = TRUE;
03203 config->centroid = TRUE;
03204 config->threshold = GILOCALIZE_THRESHOLD_LOCAL;
03205
03206
03207 p = cpl_parameterlist_find(list, "giraffe.localization.mode");
03208 s = cpl_parameter_get_string(p);
03209 if (strcmp(s, "siwc") == 0) {
03210 config->full = FALSE;
03211 }
03212
03213 p = cpl_parameterlist_find(list, "giraffe.localization.start");
03214 config->start = cpl_parameter_get_int(p);
03215
03216 p = cpl_parameterlist_find(list, "giraffe.localization.retries");
03217 config->retries = cpl_parameter_get_int(p);
03218
03219 p = cpl_parameterlist_find(list, "giraffe.localization.binsize");
03220 config->binsize = cpl_parameter_get_int(p);
03221
03222 p = cpl_parameterlist_find(list, "giraffe.localization.ewidth");
03223 config->ewidth = cpl_parameter_get_double(p);
03224
03225 p = cpl_parameterlist_find(list, "giraffe.localization.ywidth");
03226 config->ywidth = cpl_parameter_get_int(p);
03227
03228 p = cpl_parameterlist_find(list, "giraffe.localization.center");
03229 s = cpl_parameter_get_string(p);
03230 if (!strcmp(s, "hwidth")) {
03231 config->centroid = FALSE;
03232 }
03233
03234 p = cpl_parameterlist_find(list, "giraffe.localization.normalize");
03235 config->normalize = cpl_parameter_get_bool(p);
03236
03237 p = cpl_parameterlist_find(list, "giraffe.localization.threshold");
03238 s = cpl_parameter_get_string(p);
03239
03240 if (strncmp(s, "global", 6) == 0) {
03241 config->threshold = GILOCALIZE_THRESHOLD_GLOBAL;
03242 }
03243 else if (strncmp(s, "row", 3) == 0) {
03244 config->threshold = GILOCALIZE_THRESHOLD_ROW;
03245 }
03246 else {
03247 config->threshold = GILOCALIZE_THRESHOLD_LOCAL;
03248 }
03249
03250 p = cpl_parameterlist_find(list, "giraffe.localization.noise");
03251 config->noise = cpl_parameter_get_double(p);
03252
03253 p = cpl_parameterlist_find(list, "giraffe.localization.ron");
03254 config->ron = cpl_parameter_get_double(p);
03255
03256 p = cpl_parameterlist_find(list, "giraffe.localization.yorder");
03257 config->yorder = cpl_parameter_get_int(p);
03258
03259 p = cpl_parameterlist_find(list, "giraffe.localization.worder");
03260 config->worder = cpl_parameter_get_int(p);
03261
03262 p = cpl_parameterlist_find(list, "giraffe.localization.sigma");
03263 config->sigma = cpl_parameter_get_double(p);
03264
03265 p = cpl_parameterlist_find(list, "giraffe.localization.iterations");
03266 config->iterations = cpl_parameter_get_int(p);
03267
03268 p = cpl_parameterlist_find(list, "giraffe.localization.fraction");
03269 config->fraction = cpl_parameter_get_double(p);
03270
03271 return config;
03272
03273 }
03274
03275
03288 void
03289 giraffe_localize_config_destroy(GiLocalizeConfig *config)
03290 {
03291
03292 if (config) {
03293 cx_free(config);
03294 }
03295
03296 return;
03297
03298 }
03299
03300
03312 void
03313 giraffe_localize_config_add(cpl_parameterlist *list)
03314 {
03315
03316 cpl_parameter *p;
03317
03318
03319 if (list == NULL) {
03320 return;
03321 }
03322
03323 p = cpl_parameter_new_enum("giraffe.localization.mode",
03324 CPL_TYPE_STRING,
03325 "Localization mode: Use all spectra "
03326 "or the 5 SIWC spectra",
03327 "giraffe.localization",
03328 "all", 2, "all", "siwc");
03329 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-mode");
03330 cpl_parameterlist_append(list, p);
03331
03332
03333 p = cpl_parameter_new_value("giraffe.localization.start",
03334 CPL_TYPE_INT,
03335 "Bin along x-axis",
03336 "giraffe.localization",
03337 -1);
03338 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-start");
03339 cpl_parameterlist_append(list, p);
03340
03341
03342 p = cpl_parameter_new_value("giraffe.localization.retries",
03343 CPL_TYPE_INT,
03344 "Initial localization detection "
03345 "xbin retries.",
03346 "giraffe.localization",
03347 10);
03348 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-retries");
03349 cpl_parameterlist_append(list, p);
03350
03351
03352 p = cpl_parameter_new_value("giraffe.localization.binsize",
03353 CPL_TYPE_INT,
03354 "Initial localization detection "
03355 "xbin size.",
03356 "giraffe.localization",
03357 -1);
03358 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-binsize");
03359 cpl_parameterlist_append(list, p);
03360
03361
03362 p = cpl_parameter_new_value("giraffe.localization.ewidth",
03363 CPL_TYPE_DOUBLE,
03364 "Localization detection extra width.",
03365 "giraffe.localization",
03366 1.0);
03367 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-ewidth");
03368 cpl_parameterlist_append(list, p);
03369
03370
03371 p = cpl_parameter_new_value("giraffe.localization.ywidth",
03372 CPL_TYPE_INT,
03373 "Full width [pxl] of the equilizing "
03374 "filter (distance between two "
03375 "adjacent fibers).",
03376 "giraffe.localization",
03377 -1);
03378 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-ywidth");
03379 cpl_parameterlist_append(list, p);
03380
03381
03382 p = cpl_parameter_new_enum("giraffe.localization.center",
03383 CPL_TYPE_STRING,
03384 "Method used for mask center "
03385 "computation.",
03386 "giraffe.localization",
03387 "centroid", 2, "centroid",
03388 "hwidth");
03389 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-center");
03390 cpl_parameterlist_append(list, p);
03391
03392
03393 p = cpl_parameter_new_value("giraffe.localization.normalize",
03394 CPL_TYPE_BOOL,
03395 "Enable spectrum normalization along "
03396 "the dispersion axis.",
03397 "giraffe.localization",
03398 FALSE);
03399 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-norm");
03400 cpl_parameterlist_append(list, p);
03401
03402
03403 p = cpl_parameter_new_value("giraffe.localization.noise",
03404 CPL_TYPE_DOUBLE,
03405 "Threshold multiplier.",
03406 "giraffe.localization",
03407 7.0);
03408 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-noise");
03409 cpl_parameterlist_append(list, p);
03410
03411
03412 p = cpl_parameter_new_enum("giraffe.localization.threshold",
03413 CPL_TYPE_STRING,
03414 "Selects thresholding algorithm: local, "
03415 "row or global",
03416 "giraffe.localization",
03417 "local", 3, "local", "row", "global");
03418 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-threshold");
03419 cpl_parameterlist_append(list, p);
03420
03421
03422 p = cpl_parameter_new_value("giraffe.localization.ron",
03423 CPL_TYPE_DOUBLE,
03424 "New bias sigma (RON) value for dark "
03425 "subtraction",
03426 "giraffe.localization",
03427 -1.);
03428 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-ron");
03429 cpl_parameterlist_append(list, p);
03430
03431
03432 p = cpl_parameter_new_value("giraffe.localization.yorder",
03433 CPL_TYPE_INT,
03434 "Order of Chebyshev polynomial fit.",
03435 "giraffe.localization",
03436 4);
03437 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-yorder");
03438 cpl_parameterlist_append(list, p);
03439
03440
03441 p = cpl_parameter_new_value("giraffe.localization.worder",
03442 CPL_TYPE_INT,
03443 "Order of Chebyshev 2D polynomial fit.",
03444 "giraffe.localization",
03445 2);
03446 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-worder");
03447 cpl_parameterlist_append(list, p);
03448
03449
03450 p = cpl_parameter_new_value("giraffe.localization.sigma",
03451 CPL_TYPE_DOUBLE,
03452 "Localization clipping: sigma threshold "
03453 "factor",
03454 "giraffe.localization",
03455 2.5);
03456 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-sigma");
03457 cpl_parameterlist_append(list, p);
03458
03459
03460 p = cpl_parameter_new_value("giraffe.localization.iterations",
03461 CPL_TYPE_INT,
03462 "Localization clipping: number of "
03463 "iterations",
03464 "giraffe.localization",
03465 5);
03466 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-niter");
03467 cpl_parameterlist_append(list, p);
03468
03469
03470 p = cpl_parameter_new_range("giraffe.localization.fraction",
03471 CPL_TYPE_DOUBLE,
03472 "Localization clipping: minimum fraction "
03473 "of points accepted/total.",
03474 "giraffe.localization",
03475 0.9, 0.0, 1.0);
03476 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-mfrac");
03477 cpl_parameterlist_append(list, p);
03478
03479 return;
03480
03481 }