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[%" CPL_SIZE_FORMAT ",%"
01846 CPL_SIZE_FORMAT "], expected [%d,%d]", fctid,
01847 cpl_matrix_get_nrow(position->my),
01848 cpl_matrix_get_ncol(position->my), nx, ns);
01849 return;
01850 }
01851
01852 if (cpl_matrix_get_nrow(position->mw) != nx ||
01853 cpl_matrix_get_ncol(position->mw) != ns) {
01854 gi_error("%s: invalid size for position->mw[%" CPL_SIZE_FORMAT ",%"
01855 CPL_SIZE_FORMAT "], expected [%d,%d]", fctid,
01856 cpl_matrix_get_nrow(position->my),
01857 cpl_matrix_get_ncol(position->my), nx, ns);
01858 return;
01859 }
01860
01861
01862
01863
01864
01865
01866 mxraw = cpl_matrix_new(nx, 1);
01867
01868 for (x = 0; x < nx; x++) {
01869 cpl_matrix_set(mxraw, x, 0, x);
01870 }
01871
01872
01873
01874
01875
01876
01877 base = giraffe_chebyshev_base1d(0., nx, yorder, mxraw);
01878 cpl_matrix_delete(mxraw);
01879
01880 mycenter = cpl_matrix_new(cpl_matrix_get_nrow(mxok), ns);
01881 mywidth = cpl_matrix_new(1, cpl_matrix_get_nrow(mxok) * ns);
01882
01883 ycencoeff = cpl_matrix_new(yorder, 1);
01884
01885 for (nn = 0; nn < ns; nn++) {
01886
01887
01888
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901
01902 cxdouble* pixels = cpl_image_get_data_double(mz);
01903
01904 for (x = 0; x < cpl_matrix_get_nrow(mxok); x++) {
01905
01906 register cxint zx = (cxint) cpl_matrix_get(mxok, x, 0);
01907
01908 register cxdouble zz = 0.;
01909 register cxdouble yy = 0.;
01910
01911 cxdouble lower = cpl_matrix_get(mylo, x, nspectra);
01912 cxdouble upper = cpl_matrix_get(myup, x, nspectra);
01913
01914
01915 for (y = (cxint) lower; y <= (cxint) upper; y++) {
01916 yy += pixels[zx * ny + y] * y;
01917 zz += pixels[zx * ny + y];
01918 }
01919
01920 cpl_matrix_set(mycenter, x, nspectra, yy / zz);
01921 cpl_matrix_set(mywidth, 0, x * ns + nspectra, config->ewid +
01922 (upper - lower) / 2.0);
01923
01924 }
01925
01926
01927
01928
01929
01930 cpl_matrix_fill(ycencoeff, 0.);
01931 ycenfit = _giraffe_fit_border(mycenter, base, mxok, nspectra,
01932 config->sigma, config->niter,
01933 config->mfrac, ycencoeff);
01934 if (ycenfit == NULL) {
01935 cpl_msg_warning(_task, "Could not fit centroid for spectrum %d",
01936 nn);
01937 nspectra++;
01938 continue;
01939 }
01940
01941
01942
01943
01944
01945 for (x = 0; x < yorder; x++) {
01946 cpl_matrix_set(coeffs->my, x, nn,
01947 cpl_matrix_get(ycencoeff, x, 0));
01948 }
01949
01950
01951
01952
01953
01954
01955 for (x = 0; x < nx; x++) {
01956 cpl_matrix_set(position->my, x, nn,
01957 cpl_matrix_get(ycenfit, 0, x));
01958 }
01959
01960 cpl_matrix_delete(ycenfit);
01961 nspectra++;
01962
01963 }
01964
01965 GIDEBUG(cpl_image *lycenter = giraffe_matrix_create_image(mycenter);
01966 cpl_image_save(lycenter, "lycenter.fits", -32, NULL,
01967 CPL_IO_DEFAULT);
01968 cpl_image_delete(lycenter);
01969
01970 lycenter = giraffe_matrix_create_image(position->my);
01971 cpl_image_save(lycenter, "lycenterfit.fits", -32, NULL,
01972 CPL_IO_DEFAULT);
01973 cpl_image_delete(lycenter);
01974
01975 cpl_image *lyxok = giraffe_matrix_create_image(mxok);
01976 cpl_image_save(lyxok, "lyxok.fits", -32, NULL,
01977 CPL_IO_DEFAULT);
01978 cpl_image_delete(lyxok));
01979
01980
01981 cpl_msg_info(_task, "%03d spectrum positions fitted", nspectra);
01982
01983 cpl_matrix_delete(base);
01984 cpl_matrix_delete(mycenter);
01985 cpl_matrix_delete(ycencoeff);
01986
01987 if (nspectra == 0) {
01988 cpl_msg_warning(_task, "Could not fit any spectra, check number of "
01989 "good wavelength bins");
01990
01991 cpl_matrix_delete(mywidth);
01992 return;
01993 }
01994
01995
01996
01997
01998
01999 cpl_msg_info(_task, "2D fit (order %dx%d) of mask width", worder,
02000 worder);
02001
02002
02003
02004
02005
02006 mx = cpl_matrix_new(cpl_matrix_get_nrow(mxok) * nspectra, 1);
02007 my = cpl_matrix_new(cpl_matrix_get_nrow(mxok) * nspectra, 1);
02008 mw = cpl_matrix_new(1, cpl_matrix_get_nrow(mxok) * nspectra);
02009
02010 for (y = 0, nn = 0; nn < nspectra; nn++) {
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022 for (x = 0; x < cpl_matrix_get_nrow(mxok); x++) {
02023
02024 register cxint zx = (cxint) cpl_matrix_get(mxok, x, 0);
02025 register cxint lx = x * nspectra + y;
02026
02027
02028 cpl_matrix_set(mx, lx, 0, cpl_matrix_get(mxok, x, 0));
02029 cpl_matrix_set(my, lx, 0, cpl_matrix_get(position->my, zx, nn));
02030 cpl_matrix_set(mw, 0, lx, cpl_matrix_get(mywidth, 0, x * ns + y));
02031 }
02032 y++;
02033 }
02034
02035 base = giraffe_chebyshev_base2d(0., 0., nx, ny, worder, worder, mx, my);
02036
02037 cpl_matrix_delete(my);
02038 cpl_matrix_delete(mx);
02039
02040 chebcoeff = giraffe_matrix_leastsq(base, mw);
02041 cpl_matrix_delete(base);
02042 cpl_matrix_delete(mw);
02043
02044 cpl_matrix_delete(mywidth);
02045
02046 if (chebcoeff == NULL) {
02047 gi_warning("%s: error in giraffe_matrix_leastsq() for width 2D fit",
02048 fctid);
02049 return;
02050 }
02051
02052
02053
02054
02055
02056 for (nn = 0; nn < cpl_matrix_get_ncol(chebcoeff); nn++) {
02057 cpl_matrix_set(coeffs->mw, 0, nn, cpl_matrix_get(chebcoeff, 0, nn));
02058 }
02059
02060
02061
02062
02063
02064 mx = cpl_matrix_new(nx * nspectra, 1);
02065 my = cpl_matrix_new(nx * nspectra, 1);
02066
02067 for (y = 0, nn = 0; nn < nspectra; nn++) {
02068
02069
02070
02071
02072
02073
02074
02075
02076
02077
02078
02079 for (x = 0; x < nx; x++) {
02080
02081 register cxint lx = x * nspectra + y;
02082
02083 cpl_matrix_set(mx, lx, 0, x);
02084 cpl_matrix_set(my, lx, 0, cpl_matrix_get(position->my, x, nn));
02085
02086 }
02087 y++;
02088 }
02089
02090 cpl_matrix_set_size(chebcoeff, worder, worder);
02091
02092 mfitlocw = giraffe_chebyshev_fit2d(0., 0., nx, ny, chebcoeff, mx, my);
02093 cpl_matrix_delete(chebcoeff);
02094
02095 cpl_matrix_delete(my);
02096 cpl_matrix_delete(mx);
02097
02098 for (y = 0, nn = 0; nn < nspectra; nn++) {
02099
02100
02101
02102
02103
02104
02105
02106
02107
02108
02109
02110 for (x = 0; x < nx; x++) {
02111
02112 register cxint lx = x * nspectra + y;
02113
02114 cpl_matrix_set(position->mw, x, nn,
02115 cpl_matrix_get(mfitlocw, lx, 0));
02116
02117 }
02118 y++;
02119 }
02120
02121 cpl_matrix_delete(mfitlocw);
02122
02123 return;
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
02152
02153 inline static cxint
02154 _giraffe_localize_spectra(cpl_image *mzraw, cpl_image *bpixel,
02155 cpl_table *fibers, GiLocalizeMethod method,
02156 cxbool normalize, cxdouble noise,
02157 GiMaskParameters *config, GiMaskPosition *position,
02158 GiMaskPosition *coeffs)
02159 {
02160
02161 cxint n, nn;
02162 cxint nx, ny, nxok;
02163 cxint ndetect, nspectra;
02164 cxint x, y;
02165
02166 cxdouble uplost = 0.;
02167 cxdouble lolost = 0.;
02168 cxdouble avglost = 0.;
02169 cxdouble avgmask = 0.;
02170 cxdouble sigmask = 0.;
02171 cxdouble sigmean = 0.;
02172 cxdouble avgborders = 0.;
02173
02174 cxdouble *_mzraw;
02175
02176 cpl_matrix *mxok;
02177 cpl_matrix *myup;
02178 cpl_matrix *mylo;
02179 cpl_matrix *mwid;
02180
02181 cpl_image *mz = NULL;
02182 cpl_image *mznorm = NULL;
02183
02184
02185
02186 nx = cpl_image_get_size_y(mzraw);
02187 ny = cpl_image_get_size_x(mzraw);
02188 _mzraw = cpl_image_get_data_double(mzraw);
02189
02190
02191 if (normalize == TRUE) {
02192
02193 cxdouble zxmax = 0.0;
02194 cxdouble *_mzx = NULL;
02195 cxdouble *_mznorm = NULL;
02196
02197 cpl_image *mzx = NULL;
02198
02199
02200 cpl_msg_info(_task, "Using normalized spectra for localization");
02201
02202
02203
02204
02205
02206
02207
02208
02209 mznorm = cpl_image_new(ny, nx, CPL_TYPE_DOUBLE);
02210 _mznorm = cpl_image_get_data_double(mznorm);
02211
02212 mzx = cpl_image_new(1, nx, CPL_TYPE_DOUBLE);
02213 _mzx = cpl_image_get_data_double(mzx);
02214
02215
02216
02217
02218
02219
02220 for (x = 0 ; x < nx; x++) {
02221 for (y = 0 ; y < ny; y++) {
02222 _mzx[x] += _mzraw[x * ny + y];
02223 }
02224
02225
02226
02227
02228
02229 if (_mzx[x] > zxmax) {
02230 zxmax = _mzx[x];
02231 }
02232 }
02233
02234 GIDEBUG(cpl_image_save(mzx, "mzx.fits", -32, NULL, CPL_IO_DEFAULT));
02235
02236 for (x = 0 ; x < nx; x++) {
02237
02238 register cxdouble zxnorm = zxmax / _mzx[x];
02239
02240 for (y = 0 ; y < ny; y++) {
02241 _mznorm[x * ny + y] = _mzraw[x * ny + y] * zxnorm;
02242 }
02243
02244 }
02245
02246 cpl_image_delete(mzx);
02247 mz = mznorm;
02248 }
02249 else {
02250
02251
02252
02253
02254
02255 cpl_msg_info(_task, "Using raw spectra for localization");
02256 mz = mzraw;
02257 }
02258
02259
02260
02261
02262
02263
02264 nspectra = cpl_table_get_nrow(fibers);
02265
02266 mxok = cpl_matrix_new(nx, 1);
02267 myup = cpl_matrix_new(nx, nspectra);
02268 mylo = cpl_matrix_new(nx, nspectra);
02269
02270
02271
02272
02273
02274
02275 config->xbin = (config->xbin > 1) ? 2 * (config->xbin / 2) : 1;
02276
02277 GIDEBUG(cpl_image_save(mz, "mz.fits", -32, NULL, CPL_IO_DEFAULT));
02278
02279
02280
02281
02282
02283
02284 cpl_msg_info(_task, "Generating mask (%d spectra expected) ...",
02285 nspectra);
02286
02287
02288
02289 #if 0
02290 nxok = _giraffe_build_edge_mask(mz, bpixel, nspectra, noise, config,
02291 &ndetect, mxok, myup, mylo);
02292 #endif
02293
02294
02295
02296 nxok = _giraffe_build_raw_mask(mz, bpixel, nspectra, noise, config,
02297 &ndetect, mxok, myup, mylo);
02298
02299 if (nxok < 0) {
02300
02301 switch (nxok) {
02302 case -1:
02303 cpl_msg_warning(_task, "Invalid number of spectra detected: "
02304 "%d != %d", ndetect, nspectra);
02305 break;
02306
02307 case -2:
02308 cpl_msg_warning(_task, "No abcissa with good number "
02309 "of spectra");
02310 break;
02311
02312 default:
02313 cpl_msg_warning(_task, "Error while searching for spectra");
02314 break;
02315 }
02316
02317 return nxok;
02318
02319 }
02320 else {
02321 cpl_msg_info(_task, "%d spectra detected in %d wavelength bins",
02322 ndetect, nxok);
02323 }
02324
02325
02326
02327
02328
02329
02330 cpl_matrix_resize(mxok, 0, nxok - cpl_matrix_get_nrow(mxok), 0, 0);
02331 cpl_matrix_resize(myup, 0, nxok - cpl_matrix_get_nrow(myup), 0, 0);
02332 cpl_matrix_resize(mylo, 0, nxok - cpl_matrix_get_nrow(mylo), 0, 0);
02333
02334 GIDEBUG(gi_message("%s: mxok[0-%d]=[%g-%g]", __func__,
02335 cpl_matrix_get_nrow(mxok) - 1,
02336 cpl_matrix_get_min(mxok),
02337 cpl_matrix_get_max(mxok)));
02338
02339
02340 cpl_msg_info(_task, "Computing spectrum positions and widths in "
02341 "pixel range [%g,%g]", cpl_matrix_get_min(mxok),
02342 cpl_matrix_get_max(mxok));
02343
02344 if (cpl_matrix_get_nrow(mxok) <= config->ydeg) {
02345 cpl_msg_info(_task, "Not enough data points %" CPL_SIZE_FORMAT
02346 " for %d order fit", cpl_matrix_get_nrow(mxok),
02347 config->ydeg);
02348
02349 return -1;
02350 }
02351
02352 switch (method) {
02353 case GILOCALIZE_HALF_WIDTH:
02354 cpl_msg_info(_task, "Using half-width for localization");
02355 _giraffe_fit_raw_mask(mxok, myup, mylo, fibers, config,
02356 position);
02357 break;
02358
02359 case GILOCALIZE_BARYCENTER:
02360 default:
02361 cpl_msg_info(_task, "Using barycenter for localization");
02362 _giraffe_fit_raw_centroid(mz, mxok, myup, mylo, fibers, config,
02363 position, coeffs);
02364 break;
02365 }
02366
02367 if (normalize == 1) {
02368 cpl_image_delete(mznorm);
02369 }
02370
02371
02372
02373
02374
02375
02376
02377
02378
02379
02380
02381 mwid = cpl_matrix_new(nxok, nspectra);
02382
02383 for (n = 0, nn = 0; nn < cpl_table_get_nrow(fibers); nn++) {
02384
02385 for (x = 0; x < nxok; x++) {
02386 register cxint lx = (cxint) cpl_matrix_get(mxok, x, 0);
02387
02388 cxdouble lower = cpl_matrix_get(mylo, x, n);
02389 cxdouble upper = cpl_matrix_get(myup, x, n);
02390 cxdouble width = cpl_matrix_get(position->mw, lx, nn);
02391
02392 uplost += cpl_matrix_get(position->my, lx, nn) + width - upper;
02393 lolost += cpl_matrix_get(position->my, lx, nn) - width - lower;
02394
02395 avgborders += upper - lower;
02396 avgmask += width;
02397
02398 cpl_matrix_set(mwid, x, n, 2. * width);
02399 }
02400 n++;
02401 }
02402
02403 sigmean = cpl_matrix_get_mean(mwid);
02404 sigmask = giraffe_matrix_sigma_mean(mwid, sigmean);
02405 avglost = (lolost + uplost) / (nspectra * nxok);
02406 avgmask = 2.0 * avgmask / nspectra;
02407
02408 cpl_msg_info(_task, "Mask was computed using %d of %d wavelength bins",
02409 nxok, nx);
02410 cpl_msg_info(_task, "Average # of pixels per spectra: %.4g",
02411 avgmask);
02412 cpl_msg_info(_task, "Average # of in-borders pixels per spectra: %.4g",
02413 avgborders / nspectra);
02414 cpl_msg_info(_task, "Average lost pixels per spectra: %.4g",
02415 avglost);
02416 cpl_msg_info(_task, "Average lost pixels at upper border: %.4g",
02417 uplost / (nspectra * nxok));
02418 cpl_msg_info(_task, "Average lost pixels at lower border: %.4g",
02419 lolost / (nspectra * nxok));
02420 cpl_msg_info(_task, "Average spectrum width: %.4g +/- %.4g, "
02421 "(min, max) = (%.4g, %.4g)", sigmean, sigmask,
02422 cpl_matrix_get_min(mwid), cpl_matrix_get_max(mwid));
02423
02424 cpl_matrix_delete(mwid);
02425
02426 cpl_matrix_delete(mylo);
02427 cpl_matrix_delete(myup);
02428 cpl_matrix_delete(mxok);
02429
02430 return 0;
02431
02432 }
02433
02434
02435 inline static cxint
02436 _giraffe_finalize_fibers(cpl_table *fibers, cpl_matrix *locy, GiImage *mlocy,
02437 cxdouble maxoffset, cxdouble* maxshift)
02438 {
02439
02440 cxint i = 0;
02441 cxint j = 0;
02442 cxint nx = 0;
02443 cxint ny = 0;
02444 cxint _nx = 0;
02445 cxint _ny = 0;
02446 cxint nfibers = 0;
02447 cxint irow = 0;
02448
02449 cxdouble max_shift = 0.;
02450 cxdouble *positions = NULL;
02451
02452 cpl_image *_mlocy = NULL;
02453
02454
02455 if (fibers == NULL || locy == NULL || mlocy == NULL) {
02456 return -1;
02457 }
02458
02459 if (cpl_table_has_column(fibers, "RINDEX") == FALSE) {
02460 return -1;
02461 }
02462
02463 nx = cpl_matrix_get_ncol(locy);
02464 ny = cpl_matrix_get_nrow(locy);
02465
02466 nfibers = cpl_table_get_nrow(fibers);
02467
02468 _mlocy = giraffe_image_get(mlocy);
02469 _nx = cpl_image_get_size_x(_mlocy);
02470 _ny = cpl_image_get_size_y(_mlocy);
02471
02472 if (ny != _ny) {
02473 return -2;
02474 }
02475
02476 if (nfibers > _nx) {
02477 return -3;
02478 }
02479
02480 cpl_table_select_all(fibers);
02481
02482
02483
02484
02485
02486
02487 irow = (_ny - 1) / 2;
02488 positions = (cxdouble *)cpl_image_get_data(_mlocy) + irow * _nx;
02489
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499 for (i = 0; i < nfibers; i++) {
02500
02501 if (j < nx) {
02502
02503 cxint pos = cpl_table_get_int(fibers, "RINDEX", i, NULL) - 1;
02504
02505 cxdouble yc = cpl_matrix_get(locy, irow, j);
02506 cxdouble shift = fabs(yc - positions[pos]);
02507
02508 if (shift <= maxoffset) {
02509 cpl_table_unselect_row(fibers, i);
02510 ++j;
02511 }
02512 else {
02513 max_shift = CX_MAX(max_shift, shift);
02514 }
02515
02516 }
02517 }
02518
02519 cpl_table_erase_selected(fibers);
02520
02521 if (maxshift != NULL) {
02522 *maxshift = max_shift;
02523 }
02524
02525 return 0;
02526
02527 }
02528
02529
02558 cxint
02559 giraffe_localize_spectra(GiLocalization *result, GiImage *image,
02560 GiTable *fibers, GiLocalization *master,
02561 GiImage *badpixels, GiLocalizeConfig *config)
02562 {
02563
02564 const cxchar *fctid = "giraffe_localize_spectra";
02565
02566 cxint i;
02567 cxint status;
02568 cxint nrows;
02569 cxint nfibers;
02570 cxint nframes = 1;
02571 cxint ckwidth;
02572 cxint ckheight;
02573 cxint ckcount;
02574
02575 cxdouble mwidth;
02576 cxdouble conad = 0.;
02577 cxdouble bias_ron = 0.;
02578 cxdouble mask_sigma = 0.;
02579
02580 cx_string *pname;
02581
02582 cpl_propertylist *properties;
02583
02584 cpl_image *_image = giraffe_image_get(image);
02585 cpl_image *_bpixel = giraffe_image_get(badpixels);
02586 cpl_image *_result = NULL;
02587
02588 cpl_matrix *_my;
02589
02590 cpl_table *_fibers = NULL;
02591 cpl_table *fiber_setup = NULL;
02592 cpl_table *locc;
02593
02594 GiLocalizeMethod method;
02595
02596 GiInstrumentMode mode;
02597
02598 GiMaskParameters mask_config;
02599
02600 GiMaskPosition mask_position;
02601 GiMaskPosition mask_coeffs;
02602
02603
02604
02605
02606
02607
02608
02609 if (result == NULL || image == NULL || fibers == NULL || config == NULL) {
02610 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
02611 return 1;
02612 }
02613
02614 if (badpixels != NULL) {
02615 cpl_msg_debug(fctid,"Bad pixel correction is not available. Bad "
02616 "pixel map will be ignored.");
02617 }
02618
02619 _fibers = giraffe_table_get(fibers);
02620
02621 if (_fibers == NULL) {
02622 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
02623 return 1;
02624 }
02625 else {
02626 fiber_setup = _fibers;
02627 }
02628
02629 properties = giraffe_image_get_properties(image);
02630
02631
02632
02633
02634
02635
02636 nfibers = cpl_table_get_nrow(_fibers);
02637
02638 cpl_msg_info(fctid, "Setting number of fibers (%s) to %d",
02639 GIALIAS_NFIBERS, nfibers);
02640
02641 cpl_propertylist_update_int(properties, GIALIAS_NFIBERS, nfibers);
02642 cpl_propertylist_set_comment(properties, GIALIAS_NFIBERS,
02643 "Number of fibres");
02644
02645
02646 if (!cpl_propertylist_has(properties, GIALIAS_CONAD)) {
02647 cpl_msg_error(fctid, "Missing detector gain property (%s)! ",
02648 GIALIAS_CONAD);
02649 return 1;
02650 }
02651 else {
02652 conad = cpl_propertylist_get_double(properties, GIALIAS_CONAD);
02653 }
02654
02655
02656
02657
02658
02659
02660 if (config->ron > 0.) {
02661 cpl_msg_info(fctid, "Setting bias sigma value (%s) to %.5g",
02662 GIALIAS_BIASSIGMA, config->ron);
02663 cpl_propertylist_update_double(properties, GIALIAS_BIASSIGMA,
02664 config->ron);
02665 }
02666
02667 bias_ron = giraffe_propertylist_get_ron(properties);
02668 cpl_msg_info(fctid, "Bias sigma value: %.3g e-", bias_ron);
02669
02670
02671 if (cpl_propertylist_has(properties, GIALIAS_DATANCOM)) {
02672 nframes = cpl_propertylist_get_int(properties, GIALIAS_DATANCOM);
02673 }
02674
02675
02676 if (config->noise > 0.) {
02677 cpl_msg_info(fctid, "Noise multiplier: %.3g",
02678 config->noise);
02679 }
02680 else {
02681 cpl_msg_info(fctid, "Threshold multiplier: %.3g",
02682 fabs(config->noise));
02683 }
02684
02685
02686
02687
02688
02689
02690 nrows = cpl_image_get_size_y(_image);
02691
02692 if (config->start < 0) {
02693 config->start = nrows / 2;
02694 }
02695
02696
02697
02698
02699
02700
02701 mode = giraffe_get_mode(properties);
02702
02703 if (config->ywidth < 1) {
02704
02705 cpl_msg_info(fctid, "Configuring equilizing filter width from "
02706 "instrument mode");
02707
02708 switch (mode) {
02709 case GIMODE_MEDUSA:
02710 config->ywidth = 16;
02711 break;
02712
02713 case GIMODE_IFU:
02714 config->ywidth = 6;
02715 break;
02716
02717 case GIMODE_ARGUS:
02718 config->ywidth = 6;
02719 break;
02720
02721 default:
02722 cpl_msg_error(fctid, "Invalid instrument mode!");
02723 return 1;
02724 break;
02725 }
02726
02727
02728 if (!cpl_propertylist_has(properties, GIALIAS_SLITNAME)) {
02729 cpl_msg_error(fctid, "Property (%s) not found in raw image",
02730 GIALIAS_SLITNAME);
02731 return 1;
02732 }
02733 else {
02734 const cxchar *slit =
02735 cpl_propertylist_get_string(properties, GIALIAS_SLITNAME);
02736
02737 cpl_msg_info(fctid, "Setting equilizing filter to %d [pxl] "
02738 "for slit configuration `%s'", config->ywidth,
02739 slit);
02740 }
02741
02742 }
02743
02744
02745
02746
02747
02748
02749 switch (mode) {
02750 case GIMODE_MEDUSA:
02751 mwidth = GISPECTRUM_MWIDTH_MEDUSA;
02752
02753 ckwidth = 1;
02754 ckheight = 3;
02755 ckcount = 8;
02756
02757 break;
02758
02759 case GIMODE_IFU:
02760 mwidth = GISPECTRUM_MWIDTH_IFU;
02761
02762 ckwidth = 0;
02763 ckheight = 3;
02764 ckcount = 4;
02765
02766 break;
02767
02768 case GIMODE_ARGUS:
02769 mwidth = GISPECTRUM_MWIDTH_IFU;
02770
02771 ckwidth = 0;
02772 ckheight = 3;
02773 ckcount = 4;
02774
02775 break;
02776
02777 default:
02778 cpl_msg_error(fctid, "Invalid instrument mode!");
02779 return 1;
02780 break;
02781 }
02782
02783
02784
02785
02786
02787
02788 if (config->centroid == TRUE) {
02789 method = GILOCALIZE_BARYCENTER;
02790 }
02791 else {
02792 method = GILOCALIZE_HALF_WIDTH;
02793 }
02794
02795
02796
02797
02798
02799
02800
02801 mask_config.ywidth = config->ywidth;
02802 mask_config.method = config->threshold;
02803 mask_config.threshold = config->noise;
02804 mask_config.ydeg = config->yorder;
02805 mask_config.wdeg = config->worder;
02806 mask_config.ewid = config->ewidth;
02807 mask_config.wavg = mwidth;
02808 mask_config.ckdata.width = ckwidth;
02809 mask_config.ckdata.height = ckheight;
02810 mask_config.ckdata.count = ckcount;
02811 mask_config.sigma = config->sigma;
02812 mask_config.niter = config->iterations;
02813 mask_config.mfrac = config->fraction;
02814 mask_config.start = config->start;
02815 mask_config.retry = config->retries;
02816 mask_config.xbin = config->binsize;
02817
02818
02819
02820
02821
02822
02823
02824
02825
02826 if (config->noise > 0.) {
02827 mask_config.threshold *= sqrt(nframes * conad);
02828 }
02829
02830
02831
02832
02833
02834
02835
02836
02837
02838
02839
02840
02841 if (config->full != TRUE) {
02842
02843 cpl_msg_info(fctid, "Computing spectrum localization using SIWC "
02844 "spectra");
02845
02846 if (!master || !master->locy || !master->locy) {
02847 cpl_msg_error(fctid, "Required full master localization is "
02848 "missing!");
02849 return 1;
02850 }
02851
02852
02853
02854
02855
02856
02857
02858 cpl_table_unselect_all(_fibers);
02859 cpl_table_or_selected_int(_fibers, "RP", CPL_EQUAL_TO, -1);
02860
02861 fiber_setup = cpl_table_extract_selected(_fibers);
02862 nfibers = cpl_table_get_nrow(fiber_setup);
02863
02864 }
02865
02866
02867
02868
02869
02870
02871
02872 mask_position.type = GIMASK_FITTED_DATA;
02873 mask_position.my = cpl_matrix_new(nrows, nfibers);
02874 mask_position.mw = cpl_matrix_new(nrows, nfibers);
02875
02876 mask_coeffs.type = GIMASK_FIT_COEFFS;
02877 mask_coeffs.my = cpl_matrix_new(mask_config.ydeg + 1, nfibers);
02878 mask_coeffs.mw = cpl_matrix_new(1, (mask_config.wdeg + 1) *
02879 (mask_config.wdeg + 1));
02880
02881
02882
02883
02884
02885
02886
02887 _image = cpl_image_multiply_scalar_create(_image, nframes * conad);
02888
02889 mask_sigma = sqrt(nframes) * bias_ron;
02890
02891
02892
02893
02894
02895
02896 status = _giraffe_localize_spectra(_image, _bpixel, fiber_setup,
02897 method, config->normalize,
02898 mask_sigma,
02899 &mask_config, &mask_position,
02900 &mask_coeffs);
02901
02902 cpl_image_delete(_image);
02903 _image = NULL;
02904
02905 if (status) {
02906 result->locy = NULL;
02907 result->locw = NULL;
02908 result->locc = NULL;
02909 result->psf = NULL;
02910
02911 cpl_matrix_delete(mask_position.my);
02912 cpl_matrix_delete(mask_position.mw);
02913
02914 cpl_matrix_delete(mask_coeffs.my);
02915 cpl_matrix_delete(mask_coeffs.mw);
02916
02917 if (config->full != TRUE) {
02918 cpl_table_delete(fiber_setup);
02919 }
02920
02921 cpl_msg_error(fctid, "Spectrum localization computation failed!");
02922
02923 return 1;
02924 }
02925
02926
02927
02928
02929
02930
02931 if (config->full != TRUE) {
02932
02933
02934
02935
02936
02937
02938 cpl_table_delete(fiber_setup);
02939
02940 }
02941 else {
02942
02943 if (master != NULL && master->locy != NULL) {
02944
02945 cxint nf = cpl_table_get_nrow(_fibers);
02946
02947 cxdouble maxoffset = 0.5 * mask_config.wavg;
02948 cxdouble maxshift = 0.;
02949
02950
02951 cpl_msg_info(fctid, "Comparing detected and expected fiber "
02952 "positions.");
02953
02954 status = _giraffe_finalize_fibers(_fibers, mask_position.my,
02955 master->locy, maxoffset,
02956 &maxshift);
02957
02958 if (status != 0) {
02959
02960 if (status == -3) {
02961
02962 const cpl_image* mlocy = giraffe_image_get(master->locy);
02963 cxint _nf = cpl_image_get_size_x(mlocy);
02964
02965 cpl_msg_error(fctid, "More fibers (%d) than expected "
02966 "(%d) were found!", nf, _nf);
02967
02968 }
02969
02970 result->locy = NULL;
02971 result->locw = NULL;
02972 result->locc = NULL;
02973 result->psf = NULL;
02974
02975 cpl_matrix_delete(mask_position.my);
02976 cpl_matrix_delete(mask_position.mw);
02977
02978 cpl_matrix_delete(mask_coeffs.my);
02979 cpl_matrix_delete(mask_coeffs.mw);
02980
02981 if (config->full != TRUE) {
02982 cpl_table_delete(fiber_setup);
02983 }
02984
02985 cpl_msg_error(fctid, "Comparison of fiber positions "
02986 "failed!");
02987
02988 return 1;
02989 }
02990
02991 cx_assert(cpl_table_get_nrow(_fibers) <= nf);
02992
02993 cpl_msg_info(fctid, "%" CPL_SIZE_FORMAT " of %d expected fibers "
02994 "were detected.", cpl_table_get_nrow(_fibers), nf);
02995
02996 if (cpl_table_get_nrow(_fibers) < nf) {
02997 cpl_msg_debug(fctid, "Maximum offset from the expected "
02998 "position is %.2f, maximum allowed offset is %.2f",
02999 maxshift, maxoffset);
03000 cpl_msg_warning(fctid, "%" CPL_SIZE_FORMAT " fibers are "
03001 "missing!", nf - cpl_table_get_nrow(_fibers));
03002 }
03003
03004 }
03005
03006 }
03007
03008
03009
03010
03011
03012
03013
03014
03015
03016 result->locy =
03017 giraffe_image_create(CPL_TYPE_DOUBLE,
03018 cpl_matrix_get_ncol(mask_position.my),
03019 cpl_matrix_get_nrow(mask_position.my));
03020
03021 giraffe_image_copy_matrix(result->locy, mask_position.my);
03022 cpl_matrix_delete(mask_position.my);
03023
03024 giraffe_image_set_properties(result->locy, properties);
03025 properties = giraffe_image_get_properties(result->locy);
03026
03027 _result = giraffe_image_get(result->locy);
03028
03029 cpl_propertylist_set_int(properties, GIALIAS_NAXIS1,
03030 cpl_image_get_size_x(_result));
03031 cpl_propertylist_set_int(properties, GIALIAS_NAXIS2,
03032 cpl_image_get_size_y(_result));
03033 cpl_propertylist_set_int(properties, GIALIAS_BITPIX, -32);
03034 cpl_propertylist_set_double(properties, GIALIAS_BZERO, 0.);
03035 cpl_propertylist_set_double(properties, GIALIAS_BSCALE, 1.);
03036
03037 cpl_propertylist_append_int(properties, GIALIAS_LOCNX,
03038 cpl_image_get_size_y(_result));
03039 cpl_propertylist_append_int(properties, GIALIAS_LOCNS,
03040 cpl_image_get_size_x(_result));
03041
03042 if (config->centroid) {
03043 cpl_propertylist_append_string(properties, GIALIAS_LMETHOD,
03044 "BARYCENTER");
03045 }
03046 else {
03047 cpl_propertylist_append_string(properties, GIALIAS_LMETHOD,
03048 "HALF_WIDTH");
03049 }
03050
03051 if (config->normalize) {
03052 cpl_propertylist_append_int(properties, GIALIAS_LNORMALIZE,
03053 config->ywidth);
03054 }
03055 else {
03056 cpl_propertylist_append_int(properties, GIALIAS_LNORMALIZE,
03057 -config->ywidth);
03058 }
03059
03060 cpl_propertylist_append_bool(properties, GIALIAS_LFULLLOC, config->full);
03061 cpl_propertylist_append_int(properties, GIALIAS_LOCYDEG, config->yorder);
03062 cpl_propertylist_append_int(properties, GIALIAS_LOCWDEG, config->worder);
03063 cpl_propertylist_append_double(properties, GIALIAS_LEXTRAWID,
03064 config->ewidth);
03065 cpl_propertylist_append_double(properties, GIALIAS_LNOISEMULT,
03066 config->noise);
03067
03068 cpl_propertylist_append_double(properties, GIALIAS_LCLIPSIGMA,
03069 config->sigma);
03070 cpl_propertylist_append_int(properties, GIALIAS_LCLIPNITER,
03071 config->iterations);
03072 cpl_propertylist_append_double(properties, GIALIAS_LCLIPMFRAC,
03073 config->fraction);
03074
03075
03076 if (cpl_propertylist_has(properties, GIALIAS_GIRFTYPE)) {
03077 cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "LOCY");
03078 }
03079 else {
03080 cpl_propertylist_append_string(properties, GIALIAS_GIRFTYPE, "LOCY");
03081 }
03082 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE, "GIRAFFE "
03083 "localization centroid");
03084
03085
03086
03087
03088 result->locw =
03089 giraffe_image_create(CPL_TYPE_DOUBLE,
03090 cpl_matrix_get_ncol(mask_position.mw),
03091 cpl_matrix_get_nrow(mask_position.mw));
03092
03093 giraffe_image_copy_matrix(result->locw, mask_position.mw);
03094 cpl_matrix_delete(mask_position.mw);
03095
03096 giraffe_image_set_properties(result->locw, properties);
03097 properties = giraffe_image_get_properties(result->locw);
03098
03099 _result = giraffe_image_get(result->locw);
03100
03101 cpl_propertylist_set_int(properties, GIALIAS_NAXIS1,
03102 cpl_image_get_size_x(_result));
03103 cpl_propertylist_set_int(properties, GIALIAS_NAXIS2,
03104 cpl_image_get_size_y(_result));
03105
03106 if (cpl_propertylist_has(properties, GIALIAS_GIRFTYPE)) {
03107 cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE,
03108 "LOCWY");
03109 }
03110 else {
03111 cpl_propertylist_append_string(properties, GIALIAS_GIRFTYPE,
03112 "LOCWY");
03113 }
03114 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE, "GIRAFFE "
03115 "localization half-width");
03116
03117
03118
03119
03120 locc = cpl_table_new(cpl_matrix_get_ncol(mask_coeffs.my));
03121
03122 cpl_table_new_column(locc, "BUTTON", CPL_TYPE_INT);
03123 for (i = 0; i < cpl_table_get_nrow(locc); i++) {
03124 cpl_table_set_int(locc, "BUTTON", i, i);
03125 }
03126
03127 for (i = 0; i < cpl_matrix_get_nrow(mask_coeffs.my); i++) {
03128 cxchar *label = NULL;
03129
03130 cx_asprintf(&label, "YC%d", i);
03131 cpl_table_new_column(locc, label, CPL_TYPE_DOUBLE);
03132 cx_free(label);
03133 }
03134
03135
03136 result->locc = giraffe_table_create(locc, properties);
03137 cpl_table_delete(locc);
03138
03139 _my = cpl_matrix_transpose_create(mask_coeffs.my);
03140 giraffe_table_copy_matrix(result->locc, "YC0", _my);
03141 cpl_matrix_delete(_my);
03142 cpl_matrix_delete(mask_coeffs.my);
03143
03144 properties = giraffe_table_get_properties(result->locc);
03145
03146
03147
03148
03149 pname = cx_string_new();
03150
03151 for (i = 0; i < cpl_matrix_get_ncol(mask_coeffs.mw); i++) {
03152 cx_string_sprintf(pname, "%s%d", GIALIAS_LOCWIDCOEF, i);
03153 cpl_propertylist_append_double(properties, cx_string_get(pname),
03154 cpl_matrix_get(mask_coeffs.mw, 0, i));
03155 }
03156
03157 cx_string_delete(pname);
03158 cpl_matrix_delete(mask_coeffs.mw);
03159
03160 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
03161 "LOCYWCHEB");
03162 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE, "GIRAFFE "
03163 "localization fit coefficients");
03164
03165
03166
03167
03168 result->psf = NULL;
03169
03170 return 0;
03171
03172 }
03173
03174
03185 GiLocalizeConfig *
03186 giraffe_localize_config_create(cpl_parameterlist *list)
03187 {
03188
03189 const cxchar *s;
03190 cpl_parameter *p;
03191
03192 GiLocalizeConfig *config = NULL;
03193
03194
03195 if (list == NULL) {
03196 return NULL;
03197 }
03198
03199 config = cx_calloc(1, sizeof *config);
03200
03201
03202
03203
03204
03205
03206 config->full = TRUE;
03207 config->centroid = TRUE;
03208 config->threshold = GILOCALIZE_THRESHOLD_LOCAL;
03209
03210
03211 p = cpl_parameterlist_find(list, "giraffe.localization.mode");
03212 s = cpl_parameter_get_string(p);
03213 if (strcmp(s, "siwc") == 0) {
03214 config->full = FALSE;
03215 }
03216
03217 p = cpl_parameterlist_find(list, "giraffe.localization.start");
03218 config->start = cpl_parameter_get_int(p);
03219
03220 p = cpl_parameterlist_find(list, "giraffe.localization.retries");
03221 config->retries = cpl_parameter_get_int(p);
03222
03223 p = cpl_parameterlist_find(list, "giraffe.localization.binsize");
03224 config->binsize = cpl_parameter_get_int(p);
03225
03226 p = cpl_parameterlist_find(list, "giraffe.localization.ewidth");
03227 config->ewidth = cpl_parameter_get_double(p);
03228
03229 p = cpl_parameterlist_find(list, "giraffe.localization.ywidth");
03230 config->ywidth = cpl_parameter_get_int(p);
03231
03232 p = cpl_parameterlist_find(list, "giraffe.localization.center");
03233 s = cpl_parameter_get_string(p);
03234 if (!strcmp(s, "hwidth")) {
03235 config->centroid = FALSE;
03236 }
03237
03238 p = cpl_parameterlist_find(list, "giraffe.localization.normalize");
03239 config->normalize = cpl_parameter_get_bool(p);
03240
03241 p = cpl_parameterlist_find(list, "giraffe.localization.threshold");
03242 s = cpl_parameter_get_string(p);
03243
03244 if (strncmp(s, "global", 6) == 0) {
03245 config->threshold = GILOCALIZE_THRESHOLD_GLOBAL;
03246 }
03247 else if (strncmp(s, "row", 3) == 0) {
03248 config->threshold = GILOCALIZE_THRESHOLD_ROW;
03249 }
03250 else {
03251 config->threshold = GILOCALIZE_THRESHOLD_LOCAL;
03252 }
03253
03254 p = cpl_parameterlist_find(list, "giraffe.localization.noise");
03255 config->noise = cpl_parameter_get_double(p);
03256
03257 p = cpl_parameterlist_find(list, "giraffe.localization.ron");
03258 config->ron = cpl_parameter_get_double(p);
03259
03260 p = cpl_parameterlist_find(list, "giraffe.localization.yorder");
03261 config->yorder = cpl_parameter_get_int(p);
03262
03263 p = cpl_parameterlist_find(list, "giraffe.localization.worder");
03264 config->worder = cpl_parameter_get_int(p);
03265
03266 p = cpl_parameterlist_find(list, "giraffe.localization.sigma");
03267 config->sigma = cpl_parameter_get_double(p);
03268
03269 p = cpl_parameterlist_find(list, "giraffe.localization.iterations");
03270 config->iterations = cpl_parameter_get_int(p);
03271
03272 p = cpl_parameterlist_find(list, "giraffe.localization.fraction");
03273 config->fraction = cpl_parameter_get_double(p);
03274
03275 return config;
03276
03277 }
03278
03279
03292 void
03293 giraffe_localize_config_destroy(GiLocalizeConfig *config)
03294 {
03295
03296 if (config) {
03297 cx_free(config);
03298 }
03299
03300 return;
03301
03302 }
03303
03304
03316 void
03317 giraffe_localize_config_add(cpl_parameterlist *list)
03318 {
03319
03320 cpl_parameter *p;
03321
03322
03323 if (list == NULL) {
03324 return;
03325 }
03326
03327 p = cpl_parameter_new_enum("giraffe.localization.mode",
03328 CPL_TYPE_STRING,
03329 "Localization mode: Use all spectra "
03330 "or the 5 SIWC spectra",
03331 "giraffe.localization",
03332 "all", 2, "all", "siwc");
03333 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-mode");
03334 cpl_parameterlist_append(list, p);
03335
03336
03337 p = cpl_parameter_new_value("giraffe.localization.start",
03338 CPL_TYPE_INT,
03339 "Bin along x-axis",
03340 "giraffe.localization",
03341 -1);
03342 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-start");
03343 cpl_parameterlist_append(list, p);
03344
03345
03346 p = cpl_parameter_new_value("giraffe.localization.retries",
03347 CPL_TYPE_INT,
03348 "Initial localization detection "
03349 "xbin retries.",
03350 "giraffe.localization",
03351 10);
03352 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-retries");
03353 cpl_parameterlist_append(list, p);
03354
03355
03356 p = cpl_parameter_new_value("giraffe.localization.binsize",
03357 CPL_TYPE_INT,
03358 "Initial localization detection "
03359 "xbin size.",
03360 "giraffe.localization",
03361 -1);
03362 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-binsize");
03363 cpl_parameterlist_append(list, p);
03364
03365
03366 p = cpl_parameter_new_value("giraffe.localization.ewidth",
03367 CPL_TYPE_DOUBLE,
03368 "Localization detection extra width.",
03369 "giraffe.localization",
03370 1.0);
03371 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-ewidth");
03372 cpl_parameterlist_append(list, p);
03373
03374
03375 p = cpl_parameter_new_value("giraffe.localization.ywidth",
03376 CPL_TYPE_INT,
03377 "Full width [pxl] of the equilizing "
03378 "filter (distance between two "
03379 "adjacent fibers).",
03380 "giraffe.localization",
03381 -1);
03382 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-ywidth");
03383 cpl_parameterlist_append(list, p);
03384
03385
03386 p = cpl_parameter_new_enum("giraffe.localization.center",
03387 CPL_TYPE_STRING,
03388 "Method used for mask center "
03389 "computation.",
03390 "giraffe.localization",
03391 "centroid", 2, "centroid",
03392 "hwidth");
03393 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-center");
03394 cpl_parameterlist_append(list, p);
03395
03396
03397 p = cpl_parameter_new_value("giraffe.localization.normalize",
03398 CPL_TYPE_BOOL,
03399 "Enable spectrum normalization along "
03400 "the dispersion axis.",
03401 "giraffe.localization",
03402 FALSE);
03403 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-norm");
03404 cpl_parameterlist_append(list, p);
03405
03406
03407 p = cpl_parameter_new_value("giraffe.localization.noise",
03408 CPL_TYPE_DOUBLE,
03409 "Threshold multiplier.",
03410 "giraffe.localization",
03411 7.0);
03412 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-noise");
03413 cpl_parameterlist_append(list, p);
03414
03415
03416 p = cpl_parameter_new_enum("giraffe.localization.threshold",
03417 CPL_TYPE_STRING,
03418 "Selects thresholding algorithm: local, "
03419 "row or global",
03420 "giraffe.localization",
03421 "local", 3, "local", "row", "global");
03422 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-threshold");
03423 cpl_parameterlist_append(list, p);
03424
03425
03426 p = cpl_parameter_new_value("giraffe.localization.ron",
03427 CPL_TYPE_DOUBLE,
03428 "New bias sigma (RON) value for dark "
03429 "subtraction",
03430 "giraffe.localization",
03431 -1.);
03432 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-ron");
03433 cpl_parameterlist_append(list, p);
03434
03435
03436 p = cpl_parameter_new_value("giraffe.localization.yorder",
03437 CPL_TYPE_INT,
03438 "Order of Chebyshev polynomial fit.",
03439 "giraffe.localization",
03440 4);
03441 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-yorder");
03442 cpl_parameterlist_append(list, p);
03443
03444
03445 p = cpl_parameter_new_value("giraffe.localization.worder",
03446 CPL_TYPE_INT,
03447 "Order of Chebyshev 2D polynomial fit.",
03448 "giraffe.localization",
03449 2);
03450 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-worder");
03451 cpl_parameterlist_append(list, p);
03452
03453
03454 p = cpl_parameter_new_value("giraffe.localization.sigma",
03455 CPL_TYPE_DOUBLE,
03456 "Localization clipping: sigma threshold "
03457 "factor",
03458 "giraffe.localization",
03459 2.5);
03460 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-sigma");
03461 cpl_parameterlist_append(list, p);
03462
03463
03464 p = cpl_parameter_new_value("giraffe.localization.iterations",
03465 CPL_TYPE_INT,
03466 "Localization clipping: number of "
03467 "iterations",
03468 "giraffe.localization",
03469 5);
03470 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-niter");
03471 cpl_parameterlist_append(list, p);
03472
03473
03474 p = cpl_parameter_new_range("giraffe.localization.fraction",
03475 CPL_TYPE_DOUBLE,
03476 "Localization clipping: minimum fraction "
03477 "of points accepted/total.",
03478 "giraffe.localization",
03479 0.9, 0.0, 1.0);
03480 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sloc-mfrac");
03481 cpl_parameterlist_append(list, p);
03482
03483 return;
03484
03485 }