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 <math.h>
00033 #include <float.h>
00034
00035 #include <cxmemory.h>
00036 #include <cxstring.h>
00037 #include <cxstrutils.h>
00038
00039 #include <cpl_parameterlist.h>
00040 #include <cpl_matrix.h>
00041 #include <cpl_table.h>
00042 #include <cpl_msg.h>
00043
00044 #include "gimacros.h"
00045 #include "gialias.h"
00046 #include "giclip.h"
00047 #include "giarray.h"
00048 #include "giimage.h"
00049 #include "gimatrix.h"
00050 #include "giwindow.h"
00051 #include "gipsfdata.h"
00052 #include "gimodel.h"
00053 #include "gimath.h"
00054 #include "gilocalization.h"
00055 #include "gimessages.h"
00056 #include "gifiberutils.h"
00057 #include "giutils.h"
00058 #include "giextract.h"
00059
00060 #define HORNE_PURE_METHOD
00061
00062
00071 enum GiProfileId {
00072 PROFILE_PSFEXP = 1 << 1,
00073 PROFILE_PSFEXP2 = 1 << 2,
00074 PROFILE_GAUSSIAN = 1 << 3
00075 };
00076
00077 typedef enum GiProfileId GiProfileId;
00078
00079
00080
00081
00082
00083
00084 struct GiExtractOptimalConfig {
00085
00086 GiClipParams clip;
00087
00088 cxbool limits;
00089
00090 cxint bkgorder;
00091
00092 cxdouble exptime;
00093 cxdouble ron;
00094 cxdouble dark;
00095 cxdouble ewidth;
00096 };
00097
00098 typedef struct GiExtractOptimalConfig GiExtractOptimalConfig;
00099
00100
00101
00102
00103
00104
00105 struct GiExtractHorneConfig {
00106 GiClipParams clip;
00107
00108 cxdouble exptime;
00109 cxdouble ron;
00110 cxdouble dark;
00111 cxdouble ewidth;
00112 };
00113
00114 typedef struct GiExtractHorneConfig GiExtractHorneConfig;
00115
00116
00117 struct GiExtractionData {
00118 cxdouble value;
00119 cxdouble error;
00120 cxdouble position;
00121 cxdouble npixels;
00122 };
00123
00124 typedef struct GiExtractionData GiExtractionData;
00125
00126
00127 struct GiExtractionSlice {
00128 cxint fsize;
00129 cxint msize;
00130
00131 cxint nflx;
00132 cxint nbkg;
00133
00134 cpl_matrix* flux;
00135 cpl_matrix* variance;
00136 cpl_matrix* model;
00137 };
00138
00139 typedef struct GiExtractionSlice GiExtractionSlice;
00140
00141
00142 struct GiExtractionPsfLimits {
00143 cxint size;
00144
00145 cxint* ymin;
00146 cxint* ymax;
00147 };
00148
00149 typedef struct GiExtractionPsfLimits GiExtractionPsfLimits;
00150
00151
00152 struct GiExtractionWorkspace {
00153 cpl_matrix* atw;
00154 cpl_matrix* atwa;
00155 cpl_matrix* atws;
00156 cpl_matrix* c;
00157 cpl_matrix* tmp;
00158 };
00159
00160 typedef struct GiExtractionWorkspace GiExtractionWorkspace;
00161
00162
00163 struct GiVirtualSlit {
00164 cxint width;
00165
00166 cxdouble center;
00167 cxdouble extra_width;
00168
00169 cxdouble* position;
00170 cxdouble* signal;
00171 cxdouble* variance;
00172 cxdouble* fraction;
00173
00174 cxint* mask;
00175 cxint* offset;
00176 };
00177
00178 typedef struct GiVirtualSlit GiVirtualSlit;
00179
00180
00181
00182
00183
00184
00185 inline static GiExtractionSlice*
00186 _giraffe_extractionslice_new(cxint nflx, cxint ndata, cxint nbkg)
00187 {
00188
00189 GiExtractionSlice* self = cx_malloc(sizeof *self);
00190
00191 self->nflx = nflx;
00192 self->nbkg = nbkg;
00193
00194 self->fsize = nflx + nbkg;
00195 self->msize = ndata;
00196
00197 self->flux = cpl_matrix_new(self->fsize, 1);
00198 self->variance = cpl_matrix_new(self->fsize, 1);
00199 self->model = cpl_matrix_new(self->msize, 1);
00200
00201 return self;
00202
00203 }
00204
00205
00206 inline static void
00207 _giraffe_extractionslice_delete(GiExtractionSlice* self)
00208 {
00209
00210 if (self != NULL) {
00211 if (self->model != NULL) {
00212 cpl_matrix_delete(self->model);
00213 self->model = NULL;
00214 }
00215
00216 if (self->variance != NULL) {
00217 cpl_matrix_delete(self->variance);
00218 self->variance = NULL;
00219 }
00220
00221 if (self->flux != NULL) {
00222 cpl_matrix_delete(self->flux);
00223 self->flux = NULL;
00224 }
00225
00226 cx_free(self);
00227 }
00228
00229 return;
00230
00231 }
00232
00233
00234 inline static GiExtractionPsfLimits*
00235 _giraffe_extraction_psflimits_new(cxint size)
00236 {
00237
00238 GiExtractionPsfLimits* self = cx_malloc(sizeof *self);
00239
00240 self->size = size;
00241
00242 self->ymin = cx_calloc(self->size, sizeof(cxint));
00243 self->ymax = cx_calloc(self->size, sizeof(cxint));
00244
00245 return self;
00246
00247 }
00248
00249
00250 inline static void
00251 _giraffe_extraction_psflimits_delete(GiExtractionPsfLimits* self)
00252 {
00253
00254 if (self != NULL) {
00255 if (self->ymin != NULL) {
00256 cx_free(self->ymin);
00257 }
00258
00259 if (self->ymax != NULL) {
00260 cx_free(self->ymax);
00261 }
00262
00263 cx_free(self);
00264 }
00265
00266 return;
00267
00268 }
00269
00270
00271 inline static GiExtractionWorkspace*
00272 _giraffe_optimal_workspace_new(cxint m, cxint n)
00273 {
00274
00275 GiExtractionWorkspace* self = cx_malloc(sizeof *self);
00276
00277
00278 self->atw = cpl_matrix_new(m, n);
00279 self->atwa = cpl_matrix_new(m, m);
00280 self->c = cpl_matrix_new(m, m);
00281 self->atws = cpl_matrix_new(m, 1);
00282
00283 self->tmp = cpl_matrix_new(m, m);
00284
00285 return self;
00286
00287 }
00288
00289
00290 inline static void
00291 _giraffe_optimal_workspace_delete(GiExtractionWorkspace* self)
00292 {
00293
00294 if (self != NULL) {
00295 if (self->atws != NULL) {
00296 cpl_matrix_delete(self->atws);
00297 }
00298
00299 if (self->atwa != NULL) {
00300 cpl_matrix_delete(self->atwa);
00301 }
00302
00303 if (self->c != NULL) {
00304 cpl_matrix_delete(self->c);
00305 }
00306
00307 if (self->atw != NULL) {
00308 cpl_matrix_delete(self->atw);
00309 }
00310
00311 if (self->tmp != NULL) {
00312 cpl_matrix_delete(self->tmp);
00313 }
00314
00315 cx_free(self);
00316
00317 }
00318
00319 return;
00320
00321 }
00322
00323
00324
00325
00326
00327
00328 inline static void
00329 _giraffe_virtualslit_allocate(GiVirtualSlit* self)
00330 {
00331
00332 if ((self != NULL) && (self->width > 0)) {
00333
00334 self->position = cx_calloc(self->width, sizeof(cxdouble));
00335 self->signal = cx_calloc(self->width, sizeof(cxdouble));
00336 self->variance = cx_calloc(self->width, sizeof(cxdouble));
00337 self->fraction = cx_calloc(self->width, sizeof(cxdouble));
00338
00339 self->mask = cx_calloc(self->width, sizeof(cxdouble));
00340 self->offset = cx_calloc(self->width, sizeof(cxdouble));
00341
00342 }
00343
00344 return;
00345
00346 }
00347
00348
00349 inline static GiVirtualSlit*
00350 _giraffe_virtualslit_new(cxdouble extra_width)
00351 {
00352
00353 GiVirtualSlit* self = cx_calloc(1, sizeof *self);
00354
00355 self->width = 0;
00356 self->center = 0.;
00357 self->extra_width = extra_width;
00358
00359 self->position = NULL;
00360 self->signal = NULL;
00361 self->variance = NULL;
00362 self->fraction = NULL;
00363 self->mask = NULL;
00364 self->offset = NULL;
00365
00366 return self;
00367
00368 }
00369
00370
00371 inline static void
00372 _giraffe_virtualslit_clear(GiVirtualSlit* self)
00373 {
00374
00375 if (self != NULL) {
00376
00377 if (self->position != NULL) {
00378 cx_free(self->position);
00379 self->position = NULL;
00380 }
00381
00382 if (self->signal != NULL) {
00383 cx_free(self->signal);
00384 self->signal = NULL;
00385 }
00386
00387 if (self->variance != NULL) {
00388 cx_free(self->variance);
00389 self->variance = NULL;
00390 }
00391
00392 if (self->fraction != NULL) {
00393 cx_free(self->fraction);
00394 self->fraction = NULL;
00395 }
00396
00397 if (self->mask != NULL) {
00398 cx_free(self->mask);
00399 self->mask = NULL;
00400 }
00401
00402 if (self->offset != NULL) {
00403 cx_free(self->offset);
00404 self->offset = NULL;
00405 }
00406
00407 self->extra_width = 0.;
00408 self->center = 0.;
00409 self->width = 0;
00410
00411 }
00412
00413 return;
00414
00415 }
00416
00417
00418 inline static void
00419 _giraffe_virtualslit_delete(GiVirtualSlit* self)
00420 {
00421
00422 if (self != NULL) {
00423 _giraffe_virtualslit_clear(self);
00424
00425 cx_free(self);
00426 self = NULL;
00427 }
00428
00429 return;
00430
00431 }
00432
00433
00434 inline static cxint
00435 _giraffe_virtualslit_setup(GiVirtualSlit* self, cxint bin,
00436 cxdouble center, cxdouble width,
00437 const cpl_image* signal, const cpl_image* variance,
00438 const cpl_image* bpixel)
00439 {
00440
00441 register cxint ny = cpl_image_get_size_x(signal);
00442 register cxint offset = bin * cpl_image_get_size_x(signal);
00443
00444 register cxdouble lower = center - (width + self->extra_width);
00445 register cxdouble upper = center + (width + self->extra_width);
00446
00447 register cxint first = (cxint) floor(lower);
00448 register cxint last = (cxint) ceil(upper);
00449
00450 const cxdouble* s = cpl_image_get_data_double_const(signal);
00451 const cxdouble* v = cpl_image_get_data_double_const(variance);
00452
00453
00454
00455
00456
00457
00458 lower = CX_MAX(0., lower);
00459 upper = CX_MIN(ny, upper);
00460
00461 first = CX_MAX(0, first);
00462 last = CX_MIN(ny, last);
00463
00464 self->center = center;
00465 self->width = last - first + 1;
00466
00467
00468
00469
00470
00471
00472 _giraffe_virtualslit_allocate(self);
00473
00474 if (bpixel != NULL) {
00475
00476 register cxint k = 0;
00477 register cxint y = 0;
00478
00479 const cxint* _bpixel = cpl_image_get_data_int_const(bpixel);
00480
00481
00482 for (y = first; y <= last; y++) {
00483
00484 register cxint ypos = offset + y;
00485
00486 cxint ok = (_bpixel[ypos] & GIR_M_PIX_SET) == 0 ? 1 : 0;
00487
00488
00489 self->position[k] = y - center;
00490 self->fraction[k] = 1.;
00491
00492 self->signal[k] = s[ypos];
00493 self->variance[k] = v[ypos];
00494
00495 self->mask[k] = ok;
00496 self->offset[k] = ypos;
00497 ++k;
00498
00499 }
00500
00501 }
00502 else {
00503
00504 register cxint k = 0;
00505 register cxint y = 0;
00506
00507
00508 for (y = first; y <= last; y++) {
00509
00510 register cxint ypos = offset + y;
00511
00512 cxint ok = 1;
00513
00514
00515 self->position[k] = y - center;
00516 self->fraction[k] = 1.;
00517
00518 self->signal[k] = s[ypos];
00519 self->variance[k] = v[ypos];
00520
00521 self->mask[k] = ok;
00522 self->offset[k] = ypos;
00523 ++k;
00524
00525 }
00526
00527 }
00528
00529
00530
00531
00532
00533
00534
00535
00536 self->fraction[0] = ((cxdouble)first + 1.) - lower;
00537 self->fraction[self->width - 1] = upper - ((cxdouble)last - 1.);
00538
00539 return self->width;
00540
00541 }
00542
00543
00544
00545
00546
00547
00548 inline static cxint
00549 _giraffe_matrix_invert(cpl_matrix* m_inv, const cpl_matrix* m, cpl_matrix* lu)
00550 {
00551
00552 cxint i = 0;
00553 cxint status = 0;
00554 cxint n = cpl_matrix_get_ncol(m);
00555
00556 register cxint sz = n * n * sizeof(cxdouble);
00557
00558 const cxdouble* _m = cpl_matrix_get_data_const(m);
00559
00560 cxdouble* _m_inv = cpl_matrix_get_data(m_inv);
00561 cxdouble* _m_lu = cpl_matrix_get_data(lu);
00562
00563 cpl_array* perm = cpl_array_new(n, CPL_TYPE_INT);
00564
00565 register cxint* perm_data = cpl_array_get_data_int(perm);
00566
00567
00568 memset(_m_inv, 0, sz);
00569 memcpy(_m_lu, _m, sz);
00570
00571 if (cpl_matrix_decomp_lu(lu, perm, &i) != 0) {
00572 cpl_array_delete(perm);
00573 return 1;
00574 }
00575
00576
00577
00578
00579
00580
00581 for (i = 0; i < n; ++i) {
00582 _m_inv[i * n + perm_data[i]] = 1.;
00583 }
00584
00585 cpl_array_delete(perm);
00586
00587
00588 status = cpl_matrix_solve_lu(lu, m_inv, NULL);
00589
00590 if (status != 0) {
00591 cpl_matrix_delete(m_inv);
00592 return 2;
00593 }
00594
00595 return 0;
00596
00597 }
00598
00599
00600
00601
00602
00603
00604 inline static cpl_matrix*
00605 _giraffe_compute_psf(GiModel* psf, const cpl_matrix* x)
00606 {
00607
00608 register cxint i = 0;
00609 register cxint n = 0;
00610
00611 cxint status = 0;
00612
00613 const cxdouble* _x = NULL;
00614
00615 cxdouble* _y = NULL;
00616
00617 cpl_matrix* y = NULL;
00618
00619 cx_assert(psf != NULL);
00620 cx_assert(x != NULL);
00621 cx_assert(cpl_matrix_get_ncol(x) == 1);
00622
00623 n = cpl_matrix_get_nrow(x);
00624
00625 y = cpl_matrix_new(n, 1);
00626
00627 _x = cpl_matrix_get_data_const(x);
00628 _y = cpl_matrix_get_data(y);
00629
00630 for (i = 0; i < n; i++) {
00631 giraffe_model_set_argument(psf, "x", _x[i]);
00632 giraffe_model_evaluate(psf, &_y[i], &status);
00633
00634 if (status != 0) {
00635 cpl_matrix_delete(y);
00636 return NULL;
00637 }
00638 }
00639
00640 return y;
00641
00642 }
00643
00644
00645
00646
00647
00648
00649
00650 inline static cxint
00651 _giraffe_horne_extract_slit(GiExtractionData* result,
00652 const GiVirtualSlit* vslit, GiModel* psf,
00653 const GiExtractHorneConfig* config)
00654 {
00655
00656 cxint i = 0;
00657 cxint iteration = 0;
00658 cxint ngood = 0;
00659 cxint nreject = -1;
00660 cxint niter = config->clip.iterations;
00661 cxint nmin = (cxint)config->clip.fraction;
00662
00663 cxdouble sigma = config->clip.level * config->clip.level;
00664 cxdouble var = 0.;
00665 cxdouble bkg = 0.;
00666 cxdouble flx = 0.;
00667 cxdouble norm = 0.;
00668 cxdouble u = 0.;
00669 cxdouble v = 0.;
00670 cxdouble w = 0.;
00671 cxdouble fs = 0.;
00672 cxdouble fp = 0.;
00673 cxdouble* tdata = NULL;
00674 cxdouble* _mnpsf = NULL;
00675 cxdouble* variance = NULL;
00676
00677 cpl_matrix* mnpsf = NULL;
00678 cpl_matrix* mvslit = NULL;
00679
00680
00681
00682
00683
00684
00685
00686 mvslit = cpl_matrix_wrap(vslit->width, 1, vslit->position);
00687 mnpsf = _giraffe_compute_psf(psf, mvslit);
00688
00689 cpl_matrix_unwrap(mvslit);
00690 mvslit = NULL;
00691
00692 if (mnpsf == NULL) {
00693 return -1;
00694 }
00695
00696
00697
00698
00699
00700
00701
00702 _mnpsf = cpl_matrix_get_data(mnpsf);
00703
00704 norm = 0.;
00705 ngood = 0;
00706
00707 for (i = 0; i < vslit->width; ++i) {
00708 _mnpsf[i] = CX_MAX(_mnpsf[i], 0.);
00709 norm += _mnpsf[i];
00710 ngood += vslit->mask[i];
00711 }
00712
00713 for (i = 0; i < vslit->width; ++i) {
00714 _mnpsf[i] /= norm;
00715 }
00716
00717
00718
00719
00720
00721
00722 variance = cx_calloc(vslit->width, sizeof(cxdouble));
00723
00724
00725
00726
00727
00728
00729 tdata = cx_malloc(vslit->width * sizeof(cxdouble));
00730
00731 i = 0;
00732 ngood = 0;
00733
00734 while (i < vslit->width) {
00735 if (vslit->mask[i] > 0) {
00736 tdata[i] = CX_MAX(vslit->signal[i], 0.);
00737 ++ngood;
00738 }
00739 ++i;
00740 }
00741
00742 if (ngood > 0) {
00743 giraffe_array_sort(tdata, ngood);
00744 bkg = 0.5 * (tdata[0] + tdata[1]);
00745 }
00746
00747 cx_free(tdata);
00748 tdata = NULL;
00749
00750
00751
00752
00753
00754
00755 norm = 0.;
00756 flx = 0.;
00757
00758 for (i = 0; i < vslit->width; ++i) {
00759 if (vslit->mask[i] != 0) {
00760 flx += (vslit->signal[i] - bkg) * vslit->fraction[i];
00761 norm += vslit->fraction[i] * _mnpsf[i];
00762 }
00763 }
00764
00765
00766
00767
00768
00769
00770 for (i = 0; i < vslit->width; ++i) {
00771
00772 register cxdouble _flx = flx * vslit->fraction[i] * _mnpsf[i] / norm;
00773
00774 variance[i] = vslit->variance[i] + _flx + bkg;
00775
00776 }
00777
00778
00779 #if defined(HORNE_PURE_METHOD)
00780
00781
00782
00783
00784
00785 nreject = -1;
00786
00787 while ((iteration < niter) && (ngood > nmin) && (nreject != 0)) {
00788
00789 cxint imax = 0;
00790
00791 cxdouble _flx = 0.;
00792 cxdouble mmax = 0.;
00793
00794
00795 norm = 0.;
00796 var = 0.;
00797 nreject = 0;
00798
00799 for (i = 0; i < vslit->width; ++i) {
00800
00801 if (vslit->mask[i] != 0) {
00802
00803 register cxdouble data = vslit->signal[i] - bkg;
00804 register cxdouble p = _mnpsf[i];
00805
00806 norm += p * p / variance[i];
00807 _flx += p * data / variance[i];
00808 var += p;
00809
00810 }
00811
00812 }
00813
00814 flx = _flx / norm;
00815 var /= norm;
00816
00817
00818
00819
00820
00821
00822 for (i = 0; i < vslit->width; ++i) {
00823
00824 if (vslit->mask[i] != 0) {
00825
00826 cxdouble m = vslit->signal[i] - bkg - flx * _mnpsf[i];
00827
00828 variance[i] = vslit->variance[i] + fabs(flx * _mnpsf[i] + bkg);
00829
00830 m *= m / variance[i] ;
00831 if (m > mmax) {
00832 mmax = m;
00833 imax = i;
00834 }
00835
00836 }
00837
00838 }
00839
00840 if ((sigma > 0.) && (mmax > sigma)) {
00841 vslit->mask[imax] = 0;
00842 ++nreject;
00843 --ngood;
00844 }
00845
00846 ++iteration;
00847
00848 }
00849
00850 #else
00851
00852 while ((iteration < niter) && (ngood > nmin) && (nreject != 0)) {
00853
00854 cxint imax = 0;
00855
00856 cxdouble mmax = 0.;
00857
00858
00859 nreject = 0;
00860 var = 0.;
00861
00862 u = 0.;
00863 v = 0.;
00864 w = 0.;
00865 fs = 0.;
00866 fp = 0.;
00867
00868 for (i = 0; i < vslit->width; ++i) {
00869
00870 if (vslit->mask[i] != 0) {
00871
00872 register cxdouble p = _mnpsf[i];
00873 register cxdouble signal = vslit->signal[i];
00874 register cxdouble weight = 1. / variance[i];
00875
00876 u += weight;
00877 v += p * weight;
00878 w += p * p * weight;
00879
00880 fs += signal * weight;
00881 fp += p * signal * weight;
00882
00883 }
00884
00885 }
00886
00887 norm = u * w - v * v;
00888 flx = (u * fp - v * fs) / norm;
00889 bkg = (w * fs - v * fp) / norm;
00890
00891 var = u / norm;
00892
00893 for (i = 0; i < vslit->width; ++i) {
00894
00895 if (vslit->mask[i] != 0) {
00896
00897 cxdouble m = (vslit->signal[i] - bkg - flx * _mnpsf[i]);
00898
00899 variance[i] = vslit->variance[i] + fabs(flx * _mnpsf[i] + bkg);
00900
00901 m *= m / variance[i] ;
00902 if (m > mmax) {
00903 mmax = m;
00904 imax = i;
00905 }
00906
00907 }
00908
00909 }
00910
00911 if ((sigma > 0.) && (mmax > sigma)) {
00912 vslit->mask[imax] = 0;
00913 ++nreject;
00914 --ngood;
00915 }
00916
00917 }
00918
00919 #endif
00920
00921 cx_free(variance);
00922 variance = NULL;
00923
00924 cpl_matrix_delete(mnpsf);
00925 mnpsf = NULL;
00926
00927 result->value = flx;
00928 result->error = sqrt(var);
00929 result->position = vslit->center;
00930 result->npixels = ngood;
00931
00932 return 0;
00933
00934 }
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980 inline static cxint
00981 _giraffe_optimal_extract_slice(GiExtractionSlice* slice,
00982 const cpl_matrix* AT,
00983 const cpl_matrix* S,
00984 const cpl_matrix* W,
00985 GiExtractionPsfLimits* limits,
00986 GiExtractionWorkspace* ws)
00987 {
00988
00989 register cxint i = 0;
00990 register cxint n = cpl_matrix_get_ncol(AT);
00991 register cxint m = cpl_matrix_get_nrow(AT);
00992
00993 cxint status = 0;
00994
00995 const cxdouble* at = cpl_matrix_get_data_const(AT);
00996 const cxdouble* w = cpl_matrix_get_data_const(W);
00997 const cxdouble* s = cpl_matrix_get_data_const(S);
00998 const cxdouble* c = cpl_matrix_get_data_const(ws->c);
00999
01000 cxdouble* atw = cpl_matrix_get_data(ws->atw);
01001 cxdouble* atwa = cpl_matrix_get_data(ws->atwa);
01002 cxdouble* atws = cpl_matrix_get_data(ws->atws);
01003 cxdouble* sf = cpl_matrix_get_data(slice->flux);
01004 cxdouble* sv = cpl_matrix_get_data(slice->variance);
01005 cxdouble* sm = cpl_matrix_get_data(slice->model);
01006
01007
01008 for (i = 0; i < m; ++i) {
01009
01010 register cxint j = 0;
01011 register cxint im = i * m;
01012 register cxint in = i * n;
01013 register cxint ymin = limits->ymin[i];
01014 register cxint ymax = limits->ymax[i];
01015
01016
01017 atws[i] = 0.;
01018
01019 for (j = 0; j < n; ++j) {
01020
01021 register cxint k = in + j;
01022
01023
01024 atw[k] = w[j] * at[k];
01025 atws[i] += atw[k] * s[j];
01026
01027 }
01028
01029 for (j = 0; j < i; ++j) {
01030
01031 register cxint k = 0;
01032 register cxint l = im + j;
01033
01034 atwa[l] = 0.;
01035 for (k = ymin; k < ymax; ++k) {
01036 atwa[l] += atw[in + k] * at[j * n + k];
01037 }
01038
01039 atwa[j * m + i] = atwa[l];
01040
01041 }
01042
01043 atwa[im + i] = 0.;
01044
01045 for (j = ymin; j < ymax; ++j) {
01046 atwa[im + i] += atw[in + j] * at[in + j];
01047 }
01048
01049 }
01050
01051
01052 status = _giraffe_matrix_invert(ws->c, ws->atwa, ws->tmp);
01053
01054 if (status != 0) {
01055 return 1;
01056 }
01057
01058 for (i = 0; i < m; ++i) {
01059
01060 register cxint j = 0;
01061 register cxint im = i * m;
01062
01063
01064 sf[i] = 0.;
01065 sv[i] = c[im + i];
01066
01067 for (j = 0; j < m; ++j) {
01068 sf[i] += c[im + j] * atws[j];
01069 }
01070
01071 }
01072
01073 for (i = 0; i < n; ++i) {
01074
01075 register cxint j = 0;
01076
01077
01078 sm[i] = 0.;
01079
01080 for (j = 0; j < m; ++j) {
01081 sm[i] += at[j * n + i] * sf[j];
01082 }
01083
01084 }
01085
01086 return 0;
01087
01088 }
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114 inline static cxint
01115 _giraffe_extract_summation(const cpl_image* mz, const cpl_image* mvarz,
01116 const cpl_table* fibers, const cpl_image* my,
01117 const cpl_image* mw, cpl_image* mbpx,
01118 cpl_image* ms, cpl_image* mse,
01119 cpl_image* msn, cpl_image* msy)
01120 {
01121
01122 register cxint nn;
01123
01124 const cxchar* idx = NULL;
01125
01126 cxint ny = cpl_image_get_size_x(mz);
01127 cxint nfibers = cpl_table_get_nrow(fibers);
01128 cxint nspectra = cpl_image_get_size_x(my);
01129 cxint nbins = cpl_image_get_size_y(my);
01130
01131 const cxdouble* pixels = cpl_image_get_data_double_const(mz);
01132 const cxdouble* variances = cpl_image_get_data_double_const(mvarz);
01133 const cxdouble* locy = cpl_image_get_data_double_const(my);
01134 const cxdouble* locw = cpl_image_get_data_double_const(mw);
01135
01136 cxdouble* flux = cpl_image_get_data_double(ms);
01137 cxdouble* flux_error = cpl_image_get_data_double(mse);
01138 cxdouble* flux_npixels = cpl_image_get_data_double(msn);
01139 cxdouble* flux_ypos = cpl_image_get_data_double(msy);
01140
01141
01142
01143
01144
01145
01146
01147 cx_assert(nfibers <= nspectra);
01148
01149 idx = giraffe_fiberlist_query_index(fibers);
01150
01151 cx_assert(cpl_table_has_column(fibers, idx) != 0);
01152
01153 if (mbpx != NULL) {
01154
01155 const cxint* bpx = cpl_image_get_data_int(mbpx);
01156
01157 for (nn = 0; nn < nfibers; nn++) {
01158
01159 register cxint x;
01160 register cxint ns = cpl_table_get_int(fibers, idx, nn, NULL) - 1;
01161
01162
01163 for (x = 0; x < cpl_image_get_size_y(mz) && x < nbins; x++) {
01164
01165 cxint y;
01166 cxint yup, ylo;
01167 cxint lx = x * nspectra + ns;
01168 cxint sx = x * nfibers + nn;
01169
01170 cxdouble ylower = locy[lx] - locw[lx];
01171 cxdouble yupper = locy[lx] + locw[lx];
01172 cxdouble zsum = 0.;
01173 cxdouble ysum = 0.;
01174 cxdouble error2 = 0.;
01175
01176
01177 flux[sx] = 0.;
01178 flux_npixels[sx] = 0.;
01179 flux_error[sx] = 0.;
01180 flux_ypos[sx] = 0.;
01181
01182
01183
01184
01185
01186
01187 if (locw[lx] <= 0.0) {
01188 continue;
01189 }
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199 ylo = (cxint) ceil(ylower);
01200 yup = (cxint) floor(yupper);
01201
01202
01203 if (yup < 0. || ylo - 1 >= ny) {
01204 continue;
01205 }
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219 y = ylo - 1;
01220
01221 if (y >= 0) {
01222
01223 if (!(bpx[x * ny + y] & GIR_M_PIX_SET)) {
01224
01225 cxdouble extcoeff = (cxdouble)ylo - ylower;
01226 cxdouble extcoeff2 = extcoeff * extcoeff;
01227 cxdouble px = CX_MAX(pixels[x * ny + y], 0.);
01228
01229 flux[sx] = pixels[x * ny + y] * extcoeff;
01230 flux_npixels[sx] = extcoeff;
01231 error2 = variances[x * ny + y] * extcoeff2;
01232
01233 zsum = px * extcoeff;
01234 ysum = y * px * extcoeff;
01235
01236 }
01237
01238 }
01239
01240
01241
01242
01243
01244
01245 for (y = CX_MAX(ylo, 0); y < yup && y < ny; y++) {
01246
01247 if (!(bpx[x * ny + y] & GIR_M_PIX_SET)) {
01248
01249 cxdouble px = CX_MAX(pixels[x * ny + y], 0.);
01250
01251 flux[sx] += pixels[x * ny + y];
01252 flux_npixels[sx] += 1.0;
01253 error2 += variances[x * ny + y];
01254
01255 zsum += px;
01256 ysum += y * px;
01257
01258 }
01259
01260 }
01261
01262
01263
01264
01265
01266
01267 y = yup;
01268
01269 if (y < ny) {
01270
01271 if (!(bpx[x * ny + y] & GIR_M_PIX_SET)) {
01272
01273 cxdouble extcoeff = yupper - (cxdouble)yup;
01274 cxdouble extcoeff2 = extcoeff * extcoeff;
01275 cxdouble px = CX_MAX(pixels[x * ny + y], 0.);
01276
01277 flux[sx] += pixels[x * ny + y] * extcoeff;
01278 flux_npixels[sx] += extcoeff;
01279 error2 += variances[x * ny + y] * extcoeff2;
01280
01281 zsum += px * extcoeff;
01282 ysum += y * px * extcoeff;
01283
01284 }
01285
01286 }
01287
01288 flux_error[sx] = sqrt(error2);
01289
01290
01291
01292
01293 if (fabs(ysum) < DBL_EPSILON || fabs(zsum) < DBL_EPSILON) {
01294 flux_ypos[sx] = 0.5 * (yupper + ylower);
01295 }
01296 else {
01297 flux_ypos[sx] = ysum / zsum;
01298 }
01299
01300 }
01301
01302 }
01303
01304 }
01305 else {
01306
01307 for (nn = 0; nn < nfibers; nn++) {
01308
01309 register cxint x;
01310 register cxint ns = cpl_table_get_int(fibers, idx,
01311 nn, NULL) - 1;
01312
01313
01314 for (x = 0; x < cpl_image_get_size_y(mz) && x < nbins; x++) {
01315
01316 cxint y;
01317 cxint yup, ylo;
01318 cxint lx = x * nspectra + ns;
01319 cxint sx = x * nfibers + nn;
01320
01321 cxdouble yupper, ylower;
01322 cxdouble zsum = 0.;
01323 cxdouble ysum = 0.;
01324 cxdouble error2 = 0.;
01325
01326
01327 flux[sx] = 0.;
01328 flux_npixels[sx] = 0.;
01329 flux_error[sx] = 0.;
01330 flux_ypos[sx] = 0.;
01331
01332
01333
01334
01335
01336
01337 if (locw[lx] <= 0.0) {
01338 continue;
01339 }
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349 yupper = locy[lx] + locw[lx];
01350 ylower = locy[lx] - locw[lx];
01351
01352 ylo = (cxint) ceil(ylower);
01353 yup = (cxint) floor(yupper);
01354
01355
01356 if (yup < 0. || ylo - 1 >= ny) {
01357 continue;
01358 }
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372 y = ylo - 1;
01373
01374 if (y >= 0) {
01375
01376 cxdouble extcoeff = (cxdouble)ylo - ylower;
01377 cxdouble extcoeff2 = extcoeff * extcoeff;
01378 cxdouble px = CX_MAX(pixels[x * ny + y], 0.);
01379
01380 flux[sx] = pixels[x * ny + y] * extcoeff;
01381 flux_npixels[sx] = extcoeff;
01382 error2 = variances[x * ny + y] * extcoeff2;
01383
01384 zsum = px * extcoeff;
01385 ysum = y * px * extcoeff;
01386
01387 }
01388
01389
01390
01391
01392
01393
01394 for (y = CX_MAX(ylo, 0); y < yup && y < ny; y++) {
01395
01396 cxdouble px = CX_MAX(pixels[x * ny + y], 0.);
01397
01398 flux[sx] += pixels[x * ny + y];
01399 flux_npixels[sx] += 1.0;
01400 error2 += variances[x * ny + y];
01401
01402 zsum += px;
01403 ysum += y * px;
01404 }
01405
01406
01407
01408
01409
01410
01411 y = yup;
01412
01413 if (y < ny) {
01414
01415 cxdouble extcoeff = yupper - (cxdouble)yup;
01416 cxdouble extcoeff2 = extcoeff * extcoeff;
01417 cxdouble px = CX_MAX(pixels[x * ny + y], 0.);
01418
01419 flux[sx] += pixels[x * ny + y] * extcoeff;
01420 flux_npixels[sx] += extcoeff;
01421 error2 += variances[x * ny + y] * extcoeff2;
01422
01423 zsum += px * extcoeff;
01424 ysum += y * px * extcoeff;
01425
01426 }
01427
01428 flux_error[sx] = sqrt(error2);
01429
01430
01431
01432
01433 if (fabs(ysum) < DBL_EPSILON || fabs(zsum) < DBL_EPSILON) {
01434 flux_ypos[sx] = 0.5 * (yupper + ylower);
01435 }
01436 else {
01437 flux_ypos[sx] = ysum / zsum;
01438 }
01439
01440 }
01441
01442 }
01443
01444 }
01445
01446 return 0;
01447
01448 }
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472 inline static cxint
01473 _giraffe_extract_horne(const cpl_image* mz, const cpl_image* mzvar,
01474 const cpl_table* fibers, const cpl_image* my,
01475 const cpl_image* mw, const GiPsfData* psfdata,
01476 cpl_image* mbpx, cpl_image* ms, cpl_image* mse,
01477 cpl_image* msn, cpl_image* msy,
01478 const GiExtractHorneConfig* config)
01479 {
01480
01481 const cxchar* idx = NULL;
01482
01483 cxint nx = 0;
01484 cxint ny = 0;
01485 cxint fiber = 0;
01486 cxint nfibers = 0;
01487
01488 const cxdouble* locy = NULL;
01489 const cxdouble* locw = NULL;
01490 const cxdouble* width = NULL;
01491 const cxdouble* exponent = NULL;
01492
01493 GiModel* psfmodel = NULL;
01494
01495
01496 cx_assert(mz != NULL);
01497 cx_assert(mzvar != NULL);
01498
01499 cx_assert(fibers != NULL);
01500
01501 cx_assert(my != NULL);
01502 cx_assert(mw != NULL);
01503
01504 cx_assert(psfdata != NULL);
01505
01506 cx_assert(ms != NULL);
01507 cx_assert(mse != NULL);
01508 cx_assert(msn != NULL);
01509 cx_assert(msy != NULL);
01510
01511 cx_assert(config != NULL);
01512
01513 ny = cpl_image_get_size_x(mz);
01514 nx = cpl_image_get_size_y(mz);
01515 nfibers = cpl_table_get_nrow(fibers);
01516
01517 locy = cpl_image_get_data_double_const(my);
01518 locw = cpl_image_get_data_double_const(mw);
01519
01520 cx_assert((ny == cpl_image_get_size_x(mzvar)) &&
01521 (nx == cpl_image_get_size_y(mzvar)));
01522
01523 cx_assert(cpl_image_get_size_x(my) == cpl_image_get_size_x(mw));
01524 cx_assert(cpl_image_get_size_y(my) == cpl_image_get_size_y(mw));
01525
01526 cx_assert(giraffe_psfdata_fibers(psfdata) ==
01527 (cxsize)cpl_image_get_size_x(my));
01528 cx_assert(giraffe_psfdata_bins(psfdata) ==
01529 (cxsize)cpl_image_get_size_y(my));
01530
01531 cx_assert((nfibers == cpl_image_get_size_x(ms)) &&
01532 (nx == cpl_image_get_size_y(ms)));
01533 cx_assert((nfibers == cpl_image_get_size_x(mse)) &&
01534 (nx == cpl_image_get_size_y(mse)));
01535 cx_assert((nfibers == cpl_image_get_size_x(msn)) &&
01536 (nx == cpl_image_get_size_y(msn)));
01537 cx_assert((nfibers == cpl_image_get_size_x(msy)) &&
01538 (nx == cpl_image_get_size_y(msy)));
01539
01540 cx_assert((mbpx == NULL) || ((ny == cpl_image_get_size_x(mbpx)) &&
01541 (nx == cpl_image_get_size_y(mbpx))));
01542
01543
01544
01545
01546
01547
01548
01549 idx = giraffe_fiberlist_query_index(fibers);
01550
01551 cx_assert(cpl_table_has_column(fibers, idx) != 0);
01552
01553
01554
01555
01556
01557
01558
01559 if (giraffe_psfdata_contains(psfdata, "Center") == FALSE) {
01560 return -1;
01561 }
01562
01563 if (giraffe_psfdata_contains(psfdata, "Width2") == TRUE) {
01564 exponent = cpl_image_get_data_const(giraffe_psfdata_get_data(psfdata,
01565 "Width2"));
01566 }
01567
01568 width = cpl_image_get_data_const(giraffe_psfdata_get_data(psfdata,
01569 "Width1"));
01570
01571
01572
01573
01574
01575
01576 psfmodel = giraffe_model_new(giraffe_psfdata_get_model(psfdata));
01577
01578 if (psfmodel == NULL) {
01579 return -2;
01580 }
01581
01582 giraffe_model_set_parameter(psfmodel, "Center", 0.);
01583 giraffe_model_set_parameter(psfmodel, "Amplitude", 1.);
01584 giraffe_model_set_parameter(psfmodel, "Background", 0.);
01585
01586
01587
01588
01589
01590
01591 for (fiber = 0; fiber < nfibers; ++fiber) {
01592
01593 register cxint bin = 0;
01594 register cxint fidx = cpl_table_get_int(fibers, idx, fiber, NULL) - 1;
01595
01596 cxint nbins = CX_MIN(nx, cpl_image_get_size_y(my));
01597
01598 cxdouble* _ms = cpl_image_get_data_double(ms);
01599 cxdouble* _mse = cpl_image_get_data_double(mse);
01600 cxdouble* _msy = cpl_image_get_data_double(msy);
01601 cxdouble* _msn = cpl_image_get_data_double(msn);
01602
01603
01604 for (bin = 0; bin < nbins; bin++) {
01605
01606 register cxint lpos = bin * cpl_image_get_size_x(my) + fidx;
01607 register cxint spos = bin * nfibers + fiber;
01608
01609 cxint status = 0;
01610 cxint vwidth = 0;
01611
01612 register cxdouble lcenter = locy[lpos];
01613 register cxdouble lwidth = locw[lpos];
01614
01615 register cxdouble ylower = lcenter - lwidth;
01616 register cxdouble yupper = lcenter + lwidth;
01617
01618 GiVirtualSlit* vslit = NULL;
01619
01620 GiExtractionData result = {0., 0., 0., 0.};
01621
01622
01623
01624
01625
01626
01627 if ((lwidth <= 0.) || (yupper < 0.) || (ylower > ny)) {
01628 continue;
01629 }
01630
01631
01632
01633
01634
01635 vslit = _giraffe_virtualslit_new(config->ewidth);
01636
01637 vwidth = _giraffe_virtualslit_setup(vslit, bin, lcenter, lwidth,
01638 mz, mzvar, mbpx);
01639
01640 if (vwidth == 0) {
01641 _giraffe_virtualslit_delete(vslit);
01642 vslit = NULL;
01643
01644 continue;
01645 }
01646
01647
01648
01649
01650
01651
01652 giraffe_model_set_parameter(psfmodel, "Width1", width[lpos]);
01653
01654 if (exponent != NULL) {
01655 giraffe_model_set_parameter(psfmodel, "Width2",
01656 exponent[lpos]);
01657 }
01658
01659
01660
01661
01662
01663
01664
01665 status = _giraffe_horne_extract_slit(&result, vslit, psfmodel,
01666 config);
01667
01668 _giraffe_virtualslit_delete(vslit);
01669 vslit = NULL;
01670
01671 if (status != 0) {
01672
01673 giraffe_model_delete(psfmodel);
01674 psfmodel = NULL;
01675
01676 return 1;
01677 }
01678
01679 _ms[spos] = result.value;
01680 _mse[spos] = result.error;
01681 _msy[spos] = result.position;
01682 _msn[spos] = result.npixels;
01683
01684 }
01685
01686 }
01687
01688
01689 giraffe_model_delete(psfmodel);
01690 psfmodel = NULL;
01691
01692 return 0;
01693
01694 }
01695
01696
01697
01698
01699
01700
01701
01702 inline static cxint
01703 _giraffe_optimal_build_profiles(cpl_matrix* profiles,
01704 GiExtractionPsfLimits* limits,
01705 const cpl_image* my, const cpl_image* mw,
01706 const cpl_table* fibers, cxint bin,
01707 GiModel* psf, const cxdouble* width,
01708 const cxdouble* exponent, cxdouble wfactor)
01709 {
01710
01711 const cxchar* idx = giraffe_fiberlist_query_index(fibers);
01712
01713 cxint fiber = 0;
01714 cxint nfibers = cpl_table_get_nrow(fibers);
01715 cxint ny = cpl_matrix_get_ncol(profiles);
01716
01717 const cxdouble* locy = cpl_image_get_data_double_const(my);
01718 const cxdouble* locw = cpl_image_get_data_double_const(mw);
01719
01720 cxdouble* _profiles = cpl_matrix_get_data(profiles);
01721
01722 cxdouble* ypos = NULL;
01723
01724
01725 cx_assert(cpl_table_has_column(fibers, idx) != 0);
01726 cx_assert((limits == NULL) ||
01727 (cpl_matrix_get_nrow(profiles) == limits->size));
01728
01729 ypos = cx_calloc(ny, sizeof(cxdouble));
01730
01731 for (fiber = 0; fiber < nfibers; ++fiber) {
01732
01733 register cxint i = 0;
01734 register cxint y = 0;
01735 register cxint k = 0;
01736
01737 cxint fidx = cpl_table_get_int(fibers, idx, fiber, NULL) - 1;
01738 cxint lpos = bin * cpl_image_get_size_x(my) + fidx;
01739
01740 register cxdouble lcenter = locy[lpos];
01741 register cxdouble lwidth = locw[lpos];
01742
01743 register cxdouble ylower = lcenter - fabs(wfactor) * lwidth;
01744 register cxdouble yupper = lcenter + fabs(wfactor) * lwidth;
01745
01746 register cxint first = (cxint) floor(ylower);
01747 register cxint last = (cxint) ceil(yupper);
01748
01749 register cxint vwidth = 0;
01750
01751 cxdouble norm = 0.;
01752 cxdouble* _mnpsf = NULL;
01753
01754 cpl_matrix* positions = NULL;
01755 cpl_matrix* mnpsf = NULL;
01756
01757
01758
01759
01760
01761
01762 ylower = CX_MAX(0., ylower);
01763 yupper = CX_MIN(ny - 1., yupper);
01764
01765 first = CX_MAX(0, first);
01766 last = CX_MIN(ny - 1, last);
01767
01768 vwidth = last - first + 1;
01769
01770 if (limits != NULL) {
01771 limits->ymin[fiber] = first;
01772 limits->ymax[fiber] = last + 1;
01773 }
01774
01775
01776
01777
01778
01779
01780 giraffe_model_set_parameter(psf, "Width1", width[lpos]);
01781
01782 if (exponent != NULL) {
01783 giraffe_model_set_parameter(psf, "Width2", exponent[lpos]);
01784 }
01785
01786
01787
01788
01789
01790
01791 k = 0;
01792 for (y = first; y <= last; ++y) {
01793 ypos[k] = y - lcenter;
01794 ++k;
01795 }
01796
01797 positions = cpl_matrix_wrap(vwidth, 1, ypos);
01798 mnpsf = _giraffe_compute_psf(psf, positions);
01799
01800 cpl_matrix_unwrap(positions);
01801 positions = NULL;
01802
01803 if (mnpsf == NULL) {
01804 cx_free(ypos);
01805 ypos = NULL;
01806
01807 return 1;
01808 }
01809
01810 _mnpsf = cpl_matrix_get_data(mnpsf);
01811
01812 for (i = 0; i < vwidth; ++i) {
01813 _mnpsf[i] = CX_MAX(_mnpsf[i], 0.);
01814 norm += _mnpsf[i];
01815 }
01816
01817 for (i = 0; i < vwidth; ++i) {
01818 _mnpsf[i] /= norm;
01819 }
01820
01821 k = fiber * ny + first;
01822 for (y = 0; y < vwidth; ++y) {
01823 _profiles[k + y] = _mnpsf[y];
01824 }
01825
01826 cpl_matrix_delete(mnpsf);
01827 mnpsf = NULL;
01828
01829 }
01830
01831 cx_free(ypos);
01832 ypos = NULL;
01833
01834 return 0;
01835
01836 }
01837
01838
01839 inline static cxint
01840 _giraffe_extract_optimal(const cpl_image* mz, const cpl_image* mzvar,
01841 const cpl_table* fibers, const cpl_image* my,
01842 const cpl_image* mw, const GiPsfData* psfdata,
01843 cpl_image* mbpx, cpl_image* ms, cpl_image* mse,
01844 cpl_image* msm, cpl_image* msy,
01845 const GiExtractOptimalConfig* config)
01846 {
01847
01848 const cxbool nolimits = (config->limits == TRUE) ? FALSE : TRUE;
01849
01850 const cxint bkg_nc = config->bkgorder + 1;
01851 const cxint niter = config->clip.iterations;
01852
01853 register cxint i = 0;
01854
01855 cxint nx = 0;
01856 cxint ny = 0;
01857 cxint bin = 0;
01858 cxint nbins = 0;
01859 cxint nfibers = 0;
01860
01861 const cxdouble wfactor = config->ewidth;
01862 const cxdouble sigma = config->clip.level * config->clip.level;
01863 const cxdouble fraction = config->clip.fraction;
01864
01865 const cxdouble* width = NULL;
01866 const cxdouble* exponent = NULL;
01867
01868 cxdouble* _ypos = NULL;
01869 cxdouble* _bkg_base = NULL;
01870 cxdouble* _profiles = NULL;
01871 cxdouble* _signal = NULL;
01872 cxdouble* _variance = NULL;
01873 cxdouble* _mask = NULL;
01874 cxdouble* _weights = NULL;
01875
01876 cpl_matrix* ypos = NULL;
01877 cpl_matrix* bkg_base = NULL;
01878 cpl_matrix* profiles = NULL;
01879 cpl_matrix* weights = NULL;
01880 cpl_matrix* signal = NULL;
01881 cpl_matrix* variance = NULL;
01882 cpl_matrix* mask = NULL;
01883
01884 GiModel* psfmodel = NULL;
01885
01886 GiExtractionPsfLimits* limits = NULL;
01887
01888 GiExtractionSlice* slice = NULL;
01889
01890 GiExtractionWorkspace* workspace;
01891
01892
01893 cx_assert(mz != NULL);
01894 cx_assert(mzvar != NULL);
01895
01896 cx_assert(fibers != NULL);
01897
01898 cx_assert(my != NULL);
01899 cx_assert(mw != NULL);
01900
01901 cx_assert(psfdata != NULL);
01902
01903 cx_assert(ms != NULL);
01904 cx_assert(mse != NULL);
01905 cx_assert(msm != NULL);
01906 cx_assert(msy != NULL);
01907
01908 ny = cpl_image_get_size_x(mz);
01909 nx = cpl_image_get_size_y(mz);
01910
01911 nfibers = cpl_table_get_nrow(fibers);
01912 nbins = CX_MIN(nx, cpl_image_get_size_y(my));
01913
01914 cx_assert((ny == cpl_image_get_size_x(mzvar)) &&
01915 (nx == cpl_image_get_size_y(mzvar)));
01916
01917 cx_assert(cpl_image_get_size_x(my) == cpl_image_get_size_x(mw));
01918 cx_assert(cpl_image_get_size_y(my) == cpl_image_get_size_y(mw));
01919
01920 cx_assert(giraffe_psfdata_fibers(psfdata) ==
01921 (cxsize)cpl_image_get_size_x(my));
01922 cx_assert(giraffe_psfdata_bins(psfdata) ==
01923 (cxsize)cpl_image_get_size_y(my));
01924
01925 cx_assert((nfibers == cpl_image_get_size_x(ms)) &&
01926 (nx == cpl_image_get_size_y(ms)));
01927 cx_assert((nfibers == cpl_image_get_size_x(mse)) &&
01928 (nx == cpl_image_get_size_y(mse)));
01929 cx_assert((nfibers == cpl_image_get_size_x(msy)) &&
01930 (nx == cpl_image_get_size_y(msy)));
01931 cx_assert((ny == cpl_image_get_size_x(msm)) &&
01932 (nx == cpl_image_get_size_y(msm)));
01933
01934 cx_assert((mbpx == NULL) || ((ny == cpl_image_get_size_x(mbpx)) &&
01935 (nx == cpl_image_get_size_y(mbpx))));
01936
01937
01938
01939
01940
01941
01942
01943 if (giraffe_psfdata_contains(psfdata, "Center") == FALSE) {
01944 return -1;
01945 }
01946
01947 if (giraffe_psfdata_contains(psfdata, "Width2") == TRUE) {
01948 exponent = cpl_image_get_data_const(giraffe_psfdata_get_data(psfdata,
01949 "Width2"));
01950 }
01951
01952 width = cpl_image_get_data_const(giraffe_psfdata_get_data(psfdata,
01953 "Width1"));
01954
01955
01956
01957
01958
01959
01960 psfmodel = giraffe_model_new(giraffe_psfdata_get_model(psfdata));
01961
01962 if (psfmodel == NULL) {
01963 return -2;
01964 }
01965
01966 giraffe_model_set_parameter(psfmodel, "Amplitude", 1.);
01967 giraffe_model_set_parameter(psfmodel, "Background", 0.);
01968 giraffe_model_set_parameter(psfmodel, "Center", 0.);
01969
01970
01971
01972
01973
01974
01975 ypos = cpl_matrix_new(ny, 1);
01976
01977 if (ypos == NULL) {
01978 giraffe_model_delete(psfmodel);
01979 psfmodel = NULL;
01980
01981 return -3;
01982 }
01983
01984 _ypos = cpl_matrix_get_data(ypos);
01985
01986 for (i = 0; i < ny; ++i) {
01987 _ypos[i] = i;
01988 }
01989
01990
01991
01992
01993
01994
01995
01996 profiles = cpl_matrix_new(nfibers + bkg_nc, ny);
01997
01998 if (profiles == NULL) {
01999 cpl_matrix_delete(ypos);
02000 ypos = NULL;
02001
02002 giraffe_model_delete(psfmodel);
02003 psfmodel = NULL;
02004
02005 return -3;
02006 }
02007
02008 _profiles = cpl_matrix_get_data(profiles);
02009
02010
02011 signal = cpl_matrix_new(ny, 1);
02012
02013 if (signal == NULL) {
02014 cpl_matrix_delete(profiles);
02015 profiles = NULL;
02016
02017 cpl_matrix_delete(ypos);
02018 ypos = NULL;
02019
02020 giraffe_model_delete(psfmodel);
02021 psfmodel = NULL;
02022
02023 return -3;
02024 }
02025
02026 _signal = cpl_matrix_get_data(signal);
02027
02028
02029 variance = cpl_matrix_new(ny, 1);
02030
02031 if (variance == NULL) {
02032 cpl_matrix_delete(signal);
02033 signal = NULL;
02034
02035 cpl_matrix_delete(profiles);
02036 profiles = NULL;
02037
02038 cpl_matrix_delete(ypos);
02039 ypos = NULL;
02040
02041 giraffe_model_delete(psfmodel);
02042 psfmodel = NULL;
02043
02044 return -3;
02045 }
02046
02047 _variance = cpl_matrix_get_data(variance);
02048
02049
02050 mask = cpl_matrix_new(ny, 1);
02051
02052 if (mask == NULL) {
02053 cpl_matrix_delete(variance);
02054 variance = NULL;
02055
02056 cpl_matrix_delete(signal);
02057 signal = NULL;
02058
02059 cpl_matrix_delete(profiles);
02060 profiles = NULL;
02061
02062 cpl_matrix_delete(ypos);
02063 ypos = NULL;
02064
02065 giraffe_model_delete(psfmodel);
02066 psfmodel = NULL;
02067
02068 return -3;
02069 }
02070
02071 _mask = cpl_matrix_get_data(mask);
02072
02073
02074 weights = cpl_matrix_new(ny, 1);
02075
02076 if (mask == NULL) {
02077 cpl_matrix_delete(mask);
02078 mask = NULL;
02079
02080 cpl_matrix_delete(variance);
02081 variance = NULL;
02082
02083 cpl_matrix_delete(signal);
02084 signal = NULL;
02085
02086 cpl_matrix_delete(profiles);
02087 profiles = NULL;
02088
02089 cpl_matrix_delete(ypos);
02090 ypos = NULL;
02091
02092 giraffe_model_delete(psfmodel);
02093 psfmodel = NULL;
02094
02095 return -3;
02096 }
02097
02098 _weights = cpl_matrix_get_data(weights);
02099
02100
02101
02102
02103
02104
02105
02106 bkg_base = giraffe_chebyshev_base1d(0., ny, bkg_nc, ypos);
02107
02108 cpl_matrix_delete(ypos);
02109 ypos = NULL;
02110
02111 if (bkg_base == NULL) {
02112 cpl_matrix_delete(weights);
02113 weights = NULL;
02114
02115 cpl_matrix_delete(mask);
02116 mask = NULL;
02117
02118 cpl_matrix_delete(variance);
02119 variance = NULL;
02120
02121 cpl_matrix_delete(signal);
02122 signal = NULL;
02123
02124 cpl_matrix_delete(profiles);
02125 profiles = NULL;
02126
02127 cpl_matrix_delete(ypos);
02128 ypos = NULL;
02129
02130 giraffe_model_delete(psfmodel);
02131 psfmodel = NULL;
02132
02133 return -3;
02134 }
02135
02136 _bkg_base = cpl_matrix_get_data(bkg_base);
02137
02138 for (i = 0; i < bkg_nc; ++i) {
02139
02140 register cxint j = 0;
02141 register cxint offset = nfibers * ny;
02142
02143 for (j = 0; j < ny; ++j) {
02144 _profiles[i * ny + j + offset] = _bkg_base[i * ny + j];
02145 }
02146
02147 }
02148
02149 _bkg_base = NULL;
02150
02151 cpl_matrix_delete(bkg_base);
02152 bkg_base = NULL;
02153
02154
02155
02156
02157
02158
02159 slice = _giraffe_extractionslice_new(nfibers, ny, bkg_nc);
02160
02161 if (slice == NULL) {
02162 cpl_matrix_delete(weights);
02163 weights = NULL;
02164
02165 cpl_matrix_delete(mask);
02166 mask = NULL;
02167
02168 cpl_matrix_delete(variance);
02169 variance = NULL;
02170
02171 cpl_matrix_delete(signal);
02172 signal = NULL;
02173
02174 cpl_matrix_delete(profiles);
02175 profiles = NULL;
02176
02177 cpl_matrix_delete(ypos);
02178 ypos = NULL;
02179
02180 giraffe_model_delete(psfmodel);
02181 psfmodel = NULL;
02182
02183 return -3;
02184 }
02185
02186
02187 limits = _giraffe_extraction_psflimits_new(nfibers + bkg_nc);
02188
02189 if (limits == NULL) {
02190
02191 _giraffe_extractionslice_delete(slice);
02192 slice = NULL;
02193
02194 cpl_matrix_delete(weights);
02195 weights = NULL;
02196
02197 cpl_matrix_delete(mask);
02198 mask = NULL;
02199
02200 cpl_matrix_delete(variance);
02201 variance = NULL;
02202
02203 cpl_matrix_delete(signal);
02204 signal = NULL;
02205
02206 cpl_matrix_delete(profiles);
02207 profiles = NULL;
02208
02209 cpl_matrix_delete(ypos);
02210 ypos = NULL;
02211
02212 giraffe_model_delete(psfmodel);
02213 psfmodel = NULL;
02214
02215 return -3;
02216
02217 }
02218
02219 for (i = 0; i < limits->size; ++i) {
02220 limits->ymin[i] = 0;
02221 limits->ymax[i] = ny;
02222 }
02223
02224
02225
02226
02227
02228
02229 workspace = _giraffe_optimal_workspace_new(nfibers + bkg_nc, ny);
02230
02231 for (bin = 0; bin < nbins; ++bin) {
02232
02233 cxbool stop = FALSE;
02234
02235 cxint iter = 0;
02236 cxint nmin = 0;
02237 cxint ngood = ny;
02238
02239 const cxdouble* _my = cpl_image_get_data_double_const(my);
02240 const cxdouble* _mz = cpl_image_get_data_double_const(mz);
02241 const cxdouble* _mzvar = cpl_image_get_data_double_const(mzvar);
02242
02243 cxdouble* _ms = cpl_image_get_data_double(ms);
02244 cxdouble* _mse = cpl_image_get_data_double(mse);
02245 cxdouble* _msy = cpl_image_get_data_double(msy);
02246 cxdouble* _msm = cpl_image_get_data_double(msm);
02247
02248 cxint status = 0;
02249
02250 GiExtractionPsfLimits* _limits = (nolimits == FALSE) ? limits : NULL;
02251
02252 cx_assert(_mz != NULL);
02253 cx_assert(_mzvar != NULL);
02254
02255
02256
02257
02258
02259
02260
02261 status = _giraffe_optimal_build_profiles(profiles, _limits, my, mw,
02262 fibers, bin, psfmodel, width,
02263 exponent, wfactor);
02264
02265 if (status != 0) {
02266 _giraffe_optimal_workspace_delete(workspace);
02267 workspace = NULL;
02268
02269 _giraffe_extraction_psflimits_delete(limits);
02270 limits = NULL;
02271
02272 _giraffe_extractionslice_delete(slice);
02273 slice = NULL;
02274
02275 cpl_matrix_delete(weights);
02276 weights = NULL;
02277
02278 cpl_matrix_delete(mask);
02279 mask = NULL;
02280
02281 cpl_matrix_delete(variance);
02282 variance = NULL;
02283
02284 cpl_matrix_delete(signal);
02285 signal = NULL;
02286
02287 cpl_matrix_delete(profiles);
02288 profiles = NULL;
02289
02290 cpl_matrix_delete(ypos);
02291 ypos = NULL;
02292
02293 giraffe_model_delete(psfmodel);
02294 psfmodel = NULL;
02295
02296 return -4;
02297 }
02298
02299
02300
02301
02302
02303
02304
02305 if (mbpx != NULL) {
02306
02307 const cxint* _mbpx = cpl_image_get_data_int_const(mbpx);
02308
02309
02310 cx_assert(_mbpx != NULL);
02311
02312 for (i = 0; i < ny; ++i) {
02313
02314 cxbool bad = (_mbpx[bin * ny + i] & GIR_M_PIX_SET) ||
02315 (_mz[bin * ny + i] < 0.);
02316
02317 _signal[i] = _mz[bin * ny + i];
02318 _variance[i] = _signal[i] + _mzvar[bin * ny + i];
02319 _mask[i] = 1.;
02320
02321 if (bad == TRUE) {
02322 _mask[i] = 0.;
02323 --ngood;
02324 }
02325
02326 _weights[i] = _mask[i] / _variance[i];
02327
02328 }
02329
02330 }
02331 else {
02332
02333 for (i = 0; i < ny; ++i) {
02334
02335 cxbool bad = (_mz[bin * ny + i] < 0.);
02336
02337 _signal[i] = _mz[bin * ny + i];
02338 _variance[i] = _signal[i] + _mzvar[bin * ny + i];
02339 _mask[i] = 1.;
02340
02341 if (bad == TRUE) {
02342 _mask[i] = 0.;
02343 --ngood;
02344 }
02345
02346 _weights[i] = _mask[i] / _variance[i];
02347
02348 }
02349
02350 }
02351
02352
02353
02354
02355
02356
02357
02358 nmin = (cxint)(fraction * ngood);
02359
02360 while ((iter < niter) && (stop == FALSE)) {
02361
02362 cxint nreject = 0;
02363
02364 const cxdouble* _model = NULL;
02365
02366
02367 status = _giraffe_optimal_extract_slice(slice, profiles,
02368 signal, weights, limits, workspace);
02369
02370 if (status != 0) {
02371 _giraffe_optimal_workspace_delete(workspace);
02372 workspace = NULL;
02373
02374 _giraffe_extraction_psflimits_delete(limits);
02375 limits = NULL;
02376
02377 _giraffe_extractionslice_delete(slice);
02378 slice = NULL;
02379
02380 cpl_matrix_delete(weights);
02381 weights = NULL;
02382
02383 cpl_matrix_delete(mask);
02384 mask = NULL;
02385
02386 cpl_matrix_delete(variance);
02387 variance = NULL;
02388
02389 cpl_matrix_delete(signal);
02390 signal = NULL;
02391
02392 cpl_matrix_delete(profiles);
02393 profiles = NULL;
02394
02395 cpl_matrix_delete(ypos);
02396 ypos = NULL;
02397
02398 giraffe_model_delete(psfmodel);
02399 psfmodel = NULL;
02400
02401 return -5;
02402 }
02403
02404
02405
02406
02407
02408
02409 _model = cpl_matrix_get_data(slice->model);
02410
02411 for (i = 0; i < ny; ++i) {
02412
02413 if (_mask[i] > 0.) {
02414
02415 cxbool bad = FALSE;
02416 cxdouble residual = _signal[i] - _model[i];
02417
02418
02419 _variance[i] = _model[i] + _mzvar[bin * ny + i];
02420
02421 bad = (residual * residual) > (sigma * _variance[i]) ?
02422 TRUE : FALSE;
02423
02424 if (bad == TRUE) {
02425 _mask[i] = 0.;
02426 ++nreject;
02427 --ngood;
02428 }
02429
02430 _weights[i] = _mask[i] / _variance[i];
02431
02432 }
02433
02434 }
02435
02436 if ((nreject == 0) || (ngood <= nmin)) {
02437 stop = TRUE;
02438 }
02439
02440 ++iter;
02441
02442 }
02443
02444
02445
02446
02447
02448
02449
02450 memcpy(&_ms[bin * nfibers], cpl_matrix_get_data(slice->flux),
02451 slice->nflx * sizeof(cxdouble));
02452 memcpy(&_mse[bin * nfibers], cpl_matrix_get_data(slice->variance),
02453 slice->nflx * sizeof(cxdouble));
02454 memcpy(&_msm[bin * ny], cpl_matrix_get_data(slice->model),
02455 slice->msize * sizeof(cxdouble));
02456
02457 memcpy(&_msy[bin * nfibers], &_my[bin * nfibers],
02458 nfibers * sizeof(cxdouble));
02459
02460
02461
02462
02463
02464
02465 cpl_matrix_fill_window(profiles, 0., 0, 0, nfibers, ny);
02466
02467 }
02468
02469
02470
02471
02472
02473
02474 cpl_image_power(mse, 0.5);
02475
02476 _giraffe_optimal_workspace_delete(workspace);
02477 workspace = NULL;
02478
02479 _giraffe_extraction_psflimits_delete(limits);
02480 limits = NULL;
02481
02482 _giraffe_extractionslice_delete(slice);
02483 slice = NULL;
02484
02485 cpl_matrix_delete(weights);
02486 weights = NULL;
02487
02488 cpl_matrix_delete(mask);
02489 mask = NULL;
02490
02491 cpl_matrix_delete(variance);
02492 variance = NULL;
02493
02494 cpl_matrix_delete(signal);
02495 signal = NULL;
02496
02497 cpl_matrix_delete(profiles);
02498 profiles = NULL;
02499
02500 giraffe_model_delete(psfmodel);
02501 psfmodel = NULL;
02502
02503 return 0;
02504
02505 }
02506
02507
02532 cxint
02533 giraffe_extract_spectra(GiExtraction* result, GiImage* image,
02534 GiTable* fibers, GiLocalization* sloc,
02535 GiImage* bpixel, GiImage* slight,
02536 GiExtractConfig* config)
02537 {
02538
02539 const cxchar *fctid = "giraffe_extract_spectra";
02540
02541
02542 cxint ns = 0;
02543 cxint nx = 0;
02544 cxint ny = 0;
02545 cxint status = 0;
02546 cxint nframes = 1;
02547
02548 cxdouble bias_ron = 0.;
02549 cxdouble bias_sigma = 0.;
02550 cxdouble dark_value = 0.;
02551 cxdouble exptime = 0.;
02552 cxdouble conad = 1.;
02553
02554 cpl_propertylist *properties;
02555
02556 cpl_image* _image = NULL;
02557 cpl_image* _locy = NULL;
02558 cpl_image* _locw = NULL;
02559 cpl_image* _spectra = NULL;
02560 cpl_image* _error = NULL;
02561 cpl_image* _npixels = NULL;
02562 cpl_image* _centroid = NULL;
02563 cpl_image* _model = NULL;
02564
02565 cpl_table* _fibers = NULL;
02566
02567
02568
02569
02570
02571
02572 if (!result || !image || !fibers || !sloc || !config) {
02573 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
02574 return 1;
02575 }
02576
02577
02578 if ((sloc->locy == NULL) || (sloc->locw == NULL)) {
02579 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
02580 return 1;
02581 }
02582
02583
02584 if (result->spectra != NULL || result->error != NULL ||
02585 result->npixels != NULL || result->centroid != NULL ||
02586 result->model != NULL) {
02587 gi_warning("%s: Results structure at %p is not empty! Contents "
02588 "might be lost.", fctid, result);
02589 }
02590
02591
02592 _fibers = giraffe_table_get(fibers);
02593
02594 if (_fibers == NULL) {
02595 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
02596 return 1;
02597 }
02598
02599
02600 if ((config->emethod == GIEXTRACT_OPTIMAL) && (sloc->psf == NULL)) {
02601 cpl_msg_error(fctid, "Missing data: PSF profile data is required "
02602 "for optimal spectrum extraction!");
02603 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
02604
02605 return 1;
02606 }
02607
02608
02609 properties = giraffe_image_get_properties(image);
02610
02611 if (properties == NULL) {
02612 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
02613 return 1;
02614 }
02615
02616
02617 if (!cpl_propertylist_has(properties, GIALIAS_CONAD)) {
02618 cpl_msg_error(fctid, "Missing detector gain property (%s)! ",
02619 GIALIAS_CONAD);
02620 return 1;
02621 }
02622 else {
02623 conad = cpl_propertylist_get_double(properties, GIALIAS_CONAD);
02624 }
02625
02626
02627 if (!cpl_propertylist_has(properties, GIALIAS_BIASERROR)) {
02628 cpl_msg_warning(fctid, "Missing bias error property (%s)! Setting "
02629 "bias error to 0.", GIALIAS_BIASERROR);
02630 bias_sigma = 0.;
02631 }
02632 else {
02633 bias_sigma = cpl_propertylist_get_double(properties, GIALIAS_BIASERROR);
02634 }
02635
02636
02637 if (config->ron > 0.) {
02638
02639 cpl_msg_info(fctid, "Setting bias RMS property (%s) to %.4g ADU",
02640 GIALIAS_BIASSIGMA, config->ron);
02641
02642 cpl_propertylist_update_double(properties, GIALIAS_BIASSIGMA,
02643 config->ron);
02644 }
02645
02646 bias_ron = giraffe_propertylist_get_ron(properties);
02647
02648
02649 if (!cpl_propertylist_has(properties, GIALIAS_DARKVALUE)) {
02650
02651 dark_value = 0.;
02652
02653 cpl_msg_warning(fctid, "Missing dark value property (%s), will be "
02654 "set to 0.!", GIALIAS_DARKVALUE);
02655 cpl_propertylist_append_double(properties, GIALIAS_DARKVALUE,
02656 dark_value);
02657
02658 }
02659 else {
02660 dark_value = cpl_propertylist_get_double(properties,
02661 GIALIAS_DARKVALUE);
02662 }
02663
02664
02665 if (!cpl_propertylist_has(properties, GIALIAS_EXPTIME)) {
02666 cpl_msg_error(fctid, "Missing exposure time property (%s)!",
02667 GIALIAS_EXPTIME);
02668 return 1;
02669 }
02670 else {
02671 exptime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
02672 }
02673
02674
02675 if (cpl_propertylist_has(properties, GIALIAS_DATANCOM)) {
02676 nframes = cpl_propertylist_get_int(properties, GIALIAS_DATANCOM);
02677 }
02678
02679
02680
02681
02682
02683
02684
02685
02686
02687
02688 bias_sigma *= conad;
02689 dark_value *= conad;
02690
02691
02692
02693
02694
02695
02696
02697
02698
02699
02700
02701
02702
02703 _image = cpl_image_multiply_scalar_create(giraffe_image_get(image),
02704 nframes * conad);
02705
02706 _locy = giraffe_image_get(sloc->locy);
02707 _locw = giraffe_image_get(sloc->locw);
02708
02709 ny = cpl_image_get_size_x(_image);
02710 nx = cpl_image_get_size_y(_locw);
02711 ns = cpl_table_get_nrow(_fibers);
02712
02713
02714 switch (config->emethod) {
02715 case GIEXTRACT_SUM:
02716 {
02717
02718 cxint xsize = cpl_image_get_size_x(_image);
02719 cxint ysize = cpl_image_get_size_y(_image);
02720
02721 cxdouble ron_variance = bias_ron * bias_ron;
02722 cxdouble bias_variance = bias_sigma * bias_sigma;
02723 cxdouble dark_variance = dark_value * exptime;
02724
02725 cpl_image* bpixmap = NULL;
02726 cpl_image* variance = NULL;
02727
02728
02729 result->spectra = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02730 result->error = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02731 result->npixels = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02732 result->centroid = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02733 result->model = NULL;
02734
02735 _spectra = giraffe_image_get(result->spectra);
02736 _error = giraffe_image_get(result->error);
02737 _npixels = giraffe_image_get(result->npixels);
02738 _centroid = giraffe_image_get(result->centroid);
02739
02740 if (bpixel != NULL) {
02741
02742 bpixmap = giraffe_image_get(bpixel);
02743
02744 if (cpl_image_get_size_x(bpixmap) != xsize ||
02745 cpl_image_get_size_y(bpixmap) != ysize) {
02746
02747 cxbool crop = FALSE;
02748
02749 cpl_propertylist *p =
02750 giraffe_image_get_properties(bpixel);
02751
02752 GiWindow w = {1, 1, 0, 0};
02753
02754
02755 w.x1 = cpl_image_get_size_x(bpixmap);
02756 w.y1 = cpl_image_get_size_y(bpixmap);
02757
02758 if (cpl_propertylist_has(p, GIALIAS_PRSCX)) {
02759 w.x0 += cpl_propertylist_get_int(p, GIALIAS_PRSCX);
02760 crop = TRUE;
02761 }
02762
02763 if (cpl_propertylist_has(p, GIALIAS_OVSCX)) {
02764 w.x1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCX);
02765 crop = TRUE;
02766 }
02767
02768 if (cpl_propertylist_has(p, GIALIAS_PRSCY)) {
02769 w.y0 += cpl_propertylist_get_int(p, GIALIAS_PRSCY);
02770 crop = TRUE;
02771 }
02772
02773 if (cpl_propertylist_has(p, GIALIAS_OVSCY)) {
02774 w.y1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCY);
02775 crop = TRUE;
02776 }
02777
02778 if ((w.x1 - w.x0 + 1) != xsize ||
02779 (w.y1 - w.y0 + 1) != ysize) {
02780 cpl_msg_error(fctid, "Invalid bad pixel map! Image "
02781 "sizes do not match!");
02782
02783 giraffe_image_delete(result->spectra);
02784 result->spectra = NULL;
02785
02786 giraffe_image_delete(result->error);
02787 result->error = NULL;
02788
02789 giraffe_image_delete(result->npixels);
02790 result->npixels = NULL;
02791
02792 giraffe_image_delete(result->centroid);
02793 result->centroid = NULL;
02794
02795 giraffe_image_delete(result->model);
02796 result->model = NULL;
02797
02798 cpl_image_delete(_image);
02799 _image = NULL;
02800
02801 return 1;
02802 }
02803
02804 if (crop == TRUE) {
02805 bpixmap = cpl_image_extract(bpixmap, w.x0, w.y0,
02806 w.x1, w.y1);
02807 }
02808
02809 }
02810
02811 }
02812
02813 if (slight != NULL) {
02814 cpl_msg_warning(fctid, "Scattered light model will be "
02815 "ignored for extraction method `SUM'");
02816 }
02817
02818 variance = cpl_image_abs_create(_image);
02819
02820
02821
02822
02823
02824
02825
02826 cpl_image_add_scalar(variance, nframes * (ron_variance + nframes *
02827 (bias_variance + dark_variance)));
02828
02829 status = _giraffe_extract_summation(_image, variance, _fibers,
02830 _locy, _locw, bpixmap,
02831 _spectra, _error, _npixels,
02832 _centroid);
02833
02834 cpl_image_delete(variance);
02835 if (bpixmap != giraffe_image_get(bpixel)) {
02836 cpl_image_delete(bpixmap);
02837 }
02838 bpixmap = NULL;
02839
02840 break;
02841
02842 }
02843
02844 case GIEXTRACT_OPTIMAL:
02845 {
02846
02847 cxint xsize = cpl_image_get_size_x(_image);
02848 cxint ysize = cpl_image_get_size_y(_image);
02849
02850 cxdouble v0 = 0.;
02851 cxdouble ron_variance = bias_ron * bias_ron;
02852 cxdouble bias_variance = bias_sigma * bias_sigma;
02853 cxdouble dark_variance = dark_value * exptime;
02854
02855 cpl_image* variance = NULL;
02856 cpl_image* bpixmap = NULL;
02857
02858 GiExtractOptimalConfig setup;
02859
02860
02861 result->spectra = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02862 result->error = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02863 result->npixels = NULL;
02864 result->model = giraffe_image_create(CPL_TYPE_DOUBLE, ny, nx);
02865 result->centroid = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
02866
02867 _spectra = giraffe_image_get(result->spectra);
02868 _error = giraffe_image_get(result->error);
02869 _model = giraffe_image_get(result->model);
02870 _centroid = giraffe_image_get(result->centroid);
02871
02872 setup.clip.iterations = config->psf.iterations;
02873 setup.clip.level = config->psf.sigma;
02874 setup.clip.fraction = config->optimal.fraction;
02875 setup.limits = config->optimal.wfactor < 0. ? FALSE : TRUE;
02876 setup.ewidth = CX_MAX(1., fabs(config->optimal.wfactor));
02877 setup.bkgorder = config->optimal.bkgorder;
02878 setup.exptime = exptime;
02879 setup.ron = bias_sigma;
02880 setup.dark = dark_value;
02881
02882
02883 if (bpixel != NULL) {
02884
02885 bpixmap = giraffe_image_get(bpixel);
02886
02887 if (cpl_image_get_size_x(bpixmap) != xsize ||
02888 cpl_image_get_size_y(bpixmap) != ysize) {
02889
02890 cxbool crop = FALSE;
02891
02892 cpl_propertylist *p =
02893 giraffe_image_get_properties(bpixel);
02894
02895 GiWindow w = {1, 1, 0, 0};
02896
02897
02898 w.x1 = cpl_image_get_size_x(bpixmap);
02899 w.y1 = cpl_image_get_size_y(bpixmap);
02900
02901 if (cpl_propertylist_has(p, GIALIAS_PRSCX)) {
02902 w.x0 += cpl_propertylist_get_int(p, GIALIAS_PRSCX);
02903 crop = TRUE;
02904 }
02905
02906 if (cpl_propertylist_has(p, GIALIAS_OVSCX)) {
02907 w.x1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCX);
02908 crop = TRUE;
02909 }
02910
02911 if (cpl_propertylist_has(p, GIALIAS_PRSCY)) {
02912 w.y0 += cpl_propertylist_get_int(p, GIALIAS_PRSCY);
02913 crop = TRUE;
02914 }
02915
02916 if (cpl_propertylist_has(p, GIALIAS_OVSCY)) {
02917 w.y1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCY);
02918 crop = TRUE;
02919 }
02920
02921 if ((w.x1 - w.x0 + 1) != xsize ||
02922 (w.y1 - w.y0 + 1) != ysize) {
02923
02924 cpl_msg_error(fctid, "Invalid bad pixel map! "
02925 "Image sizes do not match!");
02926
02927 giraffe_image_delete(result->spectra);
02928 result->spectra = NULL;
02929
02930 giraffe_image_delete(result->error);
02931 result->error = NULL;
02932
02933 giraffe_image_delete(result->npixels);
02934 result->npixels = NULL;
02935
02936 giraffe_image_delete(result->centroid);
02937 result->centroid = NULL;
02938
02939 giraffe_image_delete(result->model);
02940 result->model = NULL;
02941
02942 cpl_image_delete(_image);
02943 _image = NULL;
02944
02945 return 1;
02946
02947 }
02948
02949 if (crop == TRUE) {
02950 bpixmap = cpl_image_extract(bpixmap, w.x0, w.y0,
02951 w.x1, w.y1);
02952 }
02953
02954 }
02955
02956 }
02957
02958 variance = cpl_image_new(xsize, ysize, CPL_TYPE_DOUBLE);
02959
02960
02961
02962
02963
02964
02965
02966 v0 = nframes * (ron_variance + nframes *
02967 (bias_variance + dark_variance));
02968
02969
02970
02971
02972
02973
02974
02975
02976 if (slight != NULL) {
02977
02978 register cxsize i = 0;
02979 register cxsize npixels = xsize * ysize;
02980
02981 const cxdouble* _slight =
02982 cpl_image_get_data_double(giraffe_image_get(slight));
02983
02984 cxdouble* _variance = cpl_image_get_data_double(variance);
02985
02986 for (i = 0; i < npixels; i++) {
02987 _variance[i] = v0 + fabs(_slight[i]) * conad * nframes;
02988 }
02989
02990 }
02991 else {
02992
02993 register cxsize i = 0;
02994 register cxsize npixels = xsize * ysize;
02995
02996 cxdouble* _variance = cpl_image_get_data_double(variance);
02997
02998 for (i = 0; i < npixels; i++) {
02999 _variance[i] = v0;
03000 }
03001
03002 }
03003
03004
03005 status = _giraffe_extract_optimal(_image, variance, _fibers,
03006 _locy, _locw, sloc->psf,
03007 bpixmap, _spectra, _error,
03008 _model, _centroid, &setup);
03009
03010 cpl_image_delete(variance);
03011 variance = NULL;
03012
03013 if (bpixmap != giraffe_image_get(bpixel)) {
03014 cpl_image_delete(bpixmap);
03015 }
03016 bpixmap = NULL;
03017
03018 break;
03019
03020 }
03021
03022 case GIEXTRACT_HORNE:
03023 {
03024
03025 cxint xsize = cpl_image_get_size_x(_image);
03026 cxint ysize = cpl_image_get_size_y(_image);
03027
03028 cxdouble v0 = 0.;
03029 cxdouble ron_variance = bias_ron * bias_ron;
03030 cxdouble bias_variance = bias_sigma * bias_sigma;
03031 cxdouble dark_variance = dark_value * exptime;
03032
03033 cpl_image* variance = NULL;
03034 cpl_image* bpixmap = NULL;
03035
03036 GiExtractHorneConfig setup;
03037
03038
03039 result->spectra = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
03040 result->error = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
03041 result->npixels = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
03042 result->centroid = giraffe_image_create(CPL_TYPE_DOUBLE, ns, nx);
03043 result->model = NULL;
03044
03045 _spectra = giraffe_image_get(result->spectra);
03046 _error = giraffe_image_get(result->error);
03047 _npixels = giraffe_image_get(result->npixels);
03048 _centroid = giraffe_image_get(result->centroid);
03049
03050 setup.clip.iterations = config->psf.iterations;
03051 setup.clip.level = config->psf.sigma;
03052 setup.clip.fraction = config->horne.mingood;
03053 setup.ewidth = config->horne.ewidth;
03054 setup.exptime = exptime;
03055 setup.ron = bias_sigma;
03056 setup.dark = dark_value;
03057
03058 if (bpixel != NULL) {
03059
03060 bpixmap = giraffe_image_get(bpixel);
03061
03062 if (cpl_image_get_size_x(bpixmap) != xsize ||
03063 cpl_image_get_size_y(bpixmap) != ysize) {
03064
03065 cxbool crop = FALSE;
03066
03067 cpl_propertylist *p =
03068 giraffe_image_get_properties(bpixel);
03069
03070 GiWindow w = {1, 1, 0, 0};
03071
03072
03073 w.x1 = cpl_image_get_size_x(bpixmap);
03074 w.y1 = cpl_image_get_size_y(bpixmap);
03075
03076 if (cpl_propertylist_has(p, GIALIAS_PRSCX)) {
03077 w.x0 += cpl_propertylist_get_int(p, GIALIAS_PRSCX);
03078 crop = TRUE;
03079 }
03080
03081 if (cpl_propertylist_has(p, GIALIAS_OVSCX)) {
03082 w.x1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCX);
03083 crop = TRUE;
03084 }
03085
03086 if (cpl_propertylist_has(p, GIALIAS_PRSCY)) {
03087 w.y0 += cpl_propertylist_get_int(p, GIALIAS_PRSCY);
03088 crop = TRUE;
03089 }
03090
03091 if (cpl_propertylist_has(p, GIALIAS_OVSCY)) {
03092 w.y1 -= cpl_propertylist_get_int(p, GIALIAS_OVSCY);
03093 crop = TRUE;
03094 }
03095
03096 if ((w.x1 - w.x0 + 1) != xsize ||
03097 (w.y1 - w.y0 + 1) != ysize) {
03098
03099 cpl_msg_error(fctid, "Invalid bad pixel map! "
03100 "Image sizes do not match!");
03101
03102 giraffe_image_delete(result->spectra);
03103 result->spectra = NULL;
03104
03105 giraffe_image_delete(result->error);
03106 result->error = NULL;
03107
03108 giraffe_image_delete(result->npixels);
03109 result->npixels = NULL;
03110
03111 giraffe_image_delete(result->centroid);
03112 result->centroid = NULL;
03113
03114 giraffe_image_delete(result->model);
03115 result->model = NULL;
03116
03117 cpl_image_delete(_image);
03118 _image = NULL;
03119
03120 return 1;
03121
03122 }
03123
03124 if (crop == TRUE) {
03125 bpixmap = cpl_image_extract(bpixmap, w.x0, w.y0,
03126 w.x1, w.y1);
03127 }
03128
03129 }
03130
03131 }
03132
03133 variance = cpl_image_new(xsize, ysize, CPL_TYPE_DOUBLE);
03134
03135
03136
03137
03138
03139
03140
03141 v0 = nframes * (ron_variance + nframes *
03142 (bias_variance + dark_variance));
03143
03144
03145
03146
03147
03148
03149
03150
03151
03152 if (slight != NULL) {
03153
03154 register cxsize i = 0;
03155 register cxsize npixels = xsize * ysize;
03156
03157 const cxdouble* _slight =
03158 cpl_image_get_data_double(giraffe_image_get(slight));
03159
03160 cxdouble* _variance = cpl_image_get_data_double(variance);
03161
03162 for (i = 0; i < npixels; i++) {
03163 _variance[i] = v0 + fabs(_slight[i]) * nframes * conad;
03164 }
03165
03166 }
03167 else {
03168
03169 register cxsize i = 0;
03170 register cxsize npixels = xsize * ysize;
03171
03172 cxdouble* _variance = cpl_image_get_data_double(variance);
03173
03174 for (i = 0; i < npixels; i++) {
03175 _variance[i] = v0;
03176 }
03177
03178 }
03179
03180
03181 status = _giraffe_extract_horne(_image, variance, _fibers,
03182 _locy, _locw, sloc->psf,
03183 bpixmap, _spectra, _error,
03184 _npixels, _centroid, &setup);
03185
03186 cpl_image_delete(variance);
03187 variance = NULL;
03188
03189 if (bpixmap != giraffe_image_get(bpixel)) {
03190 cpl_image_delete(bpixmap);
03191 }
03192 bpixmap = NULL;
03193
03194 break;
03195
03196 }
03197
03198 default:
03199 gi_message("%s: Method %d selected for spectrum extraction.",
03200 fctid, config->emethod);
03201 cpl_msg_error(fctid, "Invalid extraction method!");
03202
03203 status = 1;
03204 break;
03205 }
03206
03207 cpl_image_delete(_image);
03208 _image = NULL;
03209
03210 if (status) {
03211
03212 giraffe_image_delete(result->spectra);
03213 result->spectra = NULL;
03214
03215 giraffe_image_delete(result->error);
03216 result->error = NULL;
03217
03218 giraffe_image_delete(result->npixels);
03219 result->npixels = NULL;
03220
03221 giraffe_image_delete(result->centroid);
03222 result->centroid = NULL;
03223
03224 giraffe_image_delete(result->model);
03225 result->model = NULL;
03226
03227 cpl_msg_error(fctid, "Spectrum extraction (method %d) failed!",
03228 config->emethod);
03229
03230 cpl_image_delete(_image);
03231 _image = NULL;
03232
03233 return 1;
03234
03235 }
03236
03237
03238
03239
03240
03241
03242
03243
03244
03245
03246
03247
03248 if (result->spectra) {
03249 cpl_image_divide_scalar(giraffe_image_get(result->spectra),
03250 nframes * conad);
03251 }
03252
03253 if (result->model) {
03254 cpl_image_divide_scalar(giraffe_image_get(result->model),
03255 nframes * conad);
03256 }
03257
03258 if (result->error) {
03259 cpl_image_divide_scalar(giraffe_image_get(result->error),
03260 nframes * conad);
03261 }
03262
03263
03264
03265
03266
03267
03268 properties = giraffe_image_get_properties(image);
03269 giraffe_image_set_properties(result->spectra, properties);
03270
03271 properties = giraffe_image_get_properties(result->spectra);
03272
03273
03274
03275
03276
03277
03278
03279 giraffe_propertylist_update(properties,
03280 giraffe_image_get_properties(sloc->locy),
03281 "^ESO PRO LOC.*");
03282
03283 cpl_propertylist_set_int(properties, GIALIAS_NAXIS1,
03284 cpl_image_get_size_x(_spectra));
03285 cpl_propertylist_set_int(properties, GIALIAS_NAXIS2,
03286 cpl_image_get_size_y(_spectra));
03287
03288 cpl_propertylist_set_int(properties, GIALIAS_BITPIX, -32);
03289 cpl_propertylist_set_double(properties, GIALIAS_BZERO, 0.);
03290 cpl_propertylist_set_double(properties, GIALIAS_BSCALE, 1.);
03291
03292 cpl_propertylist_update_int(properties, GIALIAS_NFIBERS,
03293 cpl_image_get_size_x(_spectra));
03294
03295 cpl_propertylist_append_int(properties, GIALIAS_EXT_NX,
03296 cpl_image_get_size_y(_spectra));
03297 cpl_propertylist_append_int(properties, GIALIAS_EXT_NS,
03298 cpl_image_get_size_x(_spectra));
03299
03300 switch (config->emethod) {
03301 case GIEXTRACT_SUM:
03302 cpl_propertylist_append_string(properties, GIALIAS_EXT_METHOD,
03303 "SUM");
03304 cpl_propertylist_set_comment(properties, GIALIAS_EXT_METHOD,
03305 "Spectrum extraction method");
03306 break;
03307
03308 case GIEXTRACT_HORNE:
03309 {
03310
03311 cpl_propertylist_append_string(properties, GIALIAS_EXT_METHOD,
03312 "HORNE");
03313 cpl_propertylist_set_comment(properties, GIALIAS_EXT_METHOD,
03314 "Spectrum extraction method");
03315
03316 cpl_propertylist_append_string(properties, GIALIAS_EXTPSF_MODEL,
03317 config->psf.model);
03318 cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_MODEL,
03319 "PSF model used");
03320 cpl_propertylist_append_double(properties, GIALIAS_EXTPSF_SIGMA,
03321 config->psf.sigma);
03322 cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_SIGMA,
03323 "PSF fit sigma clipping threshold");
03324 cpl_propertylist_append_int(properties, GIALIAS_EXTPSF_NITER,
03325 config->psf.iterations);
03326 cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_NITER,
03327 "PSF fit maximum number of "
03328 "iterations");
03329
03330 cpl_propertylist_append_int(properties, GIALIAS_EXTHRN_EWIDTH,
03331 config->horne.ewidth);
03332 cpl_propertylist_set_comment(properties, GIALIAS_EXTHRN_EWIDTH,
03333 "Number of extra pixels used");
03334 cpl_propertylist_append_int(properties, GIALIAS_EXTHRN_MINGOOD,
03335 config->horne.mingood);
03336 cpl_propertylist_set_comment(properties, GIALIAS_EXTHRN_MINGOOD,
03337 "Minimum number of pixels to keep");
03338
03339
03340 break;
03341 }
03342
03343 case GIEXTRACT_OPTIMAL:
03344 cpl_propertylist_append_string(properties, GIALIAS_EXT_METHOD,
03345 "OPTIMAL");
03346 cpl_propertylist_set_comment(properties, GIALIAS_EXT_METHOD,
03347 "Spectrum extraction method");
03348
03349 cpl_propertylist_append_string(properties, GIALIAS_EXTPSF_MODEL,
03350 config->psf.model);
03351 cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_MODEL,
03352 "PSF model used");
03353 cpl_propertylist_append_double(properties, GIALIAS_EXTPSF_SIGMA,
03354 config->psf.sigma);
03355 cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_SIGMA,
03356 "PSF fit sigma clipping threshold");
03357 cpl_propertylist_append_int(properties, GIALIAS_EXTPSF_NITER,
03358 config->psf.iterations);
03359 cpl_propertylist_set_comment(properties, GIALIAS_EXTPSF_NITER,
03360 "PSF fit maximum number of "
03361 "iterations");
03362
03363 cpl_propertylist_append_double(properties, GIALIAS_EXTOPT_FRACTION,
03364 config->optimal.fraction);
03365 cpl_propertylist_set_comment(properties, GIALIAS_EXTOPT_FRACTION,
03366 "Minimum fraction of pixels used.");
03367 cpl_propertylist_append_double(properties, GIALIAS_EXTOPT_WFACTOR,
03368 config->optimal.wfactor);
03369 cpl_propertylist_set_comment(properties, GIALIAS_EXTOPT_WFACTOR,
03370 "Multiple of the fiber PSF half "
03371 "width used for spectrum "
03372 "extraction.");
03373 cpl_propertylist_append_int(properties, GIALIAS_EXTOPT_BGORDER,
03374 config->optimal.bkgorder);
03375 cpl_propertylist_set_comment(properties, GIALIAS_EXTOPT_BGORDER,
03376 "Order of the background polynomial "
03377 "model along the spatial direction.");
03378
03379 break;
03380
03381 default:
03382 break;
03383 }
03384
03385 cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE, "EXTSP");
03386 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03387 "Extracted spectra");
03388
03389
03390
03391
03392
03393
03394 giraffe_image_set_properties(result->error, properties);
03395 properties = giraffe_image_get_properties(result->error);
03396
03397 cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "EXTERRS");
03398 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03399 "Extracted spectra errors");
03400
03401
03402
03403
03404
03405
03406 giraffe_image_set_properties(result->centroid, properties);
03407 properties = giraffe_image_get_properties(result->centroid);
03408
03409 cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "EXTYCEN");
03410 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03411 "Extracted spectra centroids");
03412
03413
03414
03415
03416
03417
03418 if (result->npixels != NULL) {
03419 giraffe_image_set_properties(result->npixels, properties);
03420 properties = giraffe_image_get_properties(result->npixels);
03421
03422 cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "EXTNPIX");
03423 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03424 "Extracted spectra npixels");
03425 }
03426
03427
03428
03429
03430
03431
03432 if (result->model != NULL) {
03433 giraffe_image_set_properties(result->model, properties);
03434 properties = giraffe_image_get_properties(result->model);
03435
03436 cpl_propertylist_set_string(properties, GIALIAS_GIRFTYPE, "EXTMODEL");
03437 cpl_propertylist_set_comment(properties, GIALIAS_GIRFTYPE,
03438 "Model spectra used for extraction");
03439 }
03440
03441 return 0;
03442
03443 }
03444
03445
03456 GiExtractConfig*
03457 giraffe_extract_config_create(cpl_parameterlist* list)
03458 {
03459
03460 const cxchar* s;
03461 cpl_parameter* p;
03462
03463 GiExtractConfig* config = NULL;
03464
03465
03466 if (!list) {
03467 return NULL;
03468 }
03469
03470 config = cx_calloc(1, sizeof *config);
03471
03472 p = cpl_parameterlist_find(list, "giraffe.extraction.method");
03473 s = cpl_parameter_get_string(p);
03474 if (!strcmp(s, "OPTIMAL")) {
03475 config->emethod = GIEXTRACT_OPTIMAL;
03476 }
03477 else if (!strcmp(s, "HORNE")) {
03478 config->emethod = GIEXTRACT_HORNE;
03479 }
03480 else {
03481 config->emethod = GIEXTRACT_SUM;
03482 }
03483
03484 p = cpl_parameterlist_find(list, "giraffe.extraction.ron");
03485 config->ron = cpl_parameter_get_double(p);
03486
03487 p = cpl_parameterlist_find(list, "giraffe.extraction.psf.model");
03488 config->psf.model = cx_strdup(cpl_parameter_get_string(p));
03489
03490 p = cpl_parameterlist_find(list, "giraffe.extraction.psf.sigma");
03491 config->psf.sigma = cpl_parameter_get_double(p);
03492
03493 p = cpl_parameterlist_find(list, "giraffe.extraction.psf.iterations");
03494 config->psf.iterations = cpl_parameter_get_int(p);
03495
03496
03497 p = cpl_parameterlist_find(list, "giraffe.extraction.horne.extrawidth");
03498 config->horne.ewidth = cpl_parameter_get_int(p);
03499
03500 p = cpl_parameterlist_find(list, "giraffe.extraction.horne.mingood");
03501 config->horne.mingood = cpl_parameter_get_double(p);
03502
03503
03504 p = cpl_parameterlist_find(list, "giraffe.extraction.optimal.fraction");
03505 config->optimal.fraction = cpl_parameter_get_double(p);
03506
03507 p = cpl_parameterlist_find(list, "giraffe.extraction.optimal.wfactor");
03508 config->optimal.wfactor = cpl_parameter_get_double(p);
03509
03510 p = cpl_parameterlist_find(list, "giraffe.extraction.optimal.bkgorder");
03511 config->optimal.bkgorder = cpl_parameter_get_int(p);
03512
03513 return config;
03514
03515 }
03516
03517
03530 void
03531 giraffe_extract_config_destroy(GiExtractConfig* config)
03532 {
03533
03534 if (config) {
03535
03536 if (config->psf.model) {
03537 cx_free(config->psf.model);
03538 }
03539
03540 cx_free(config);
03541
03542 }
03543
03544 return;
03545
03546 }
03547
03548
03560 void
03561 giraffe_extract_config_add(cpl_parameterlist* list)
03562 {
03563
03564 cpl_parameter* p = NULL;
03565
03566
03567 if (list == NULL) {
03568 return;
03569 }
03570
03571 p = cpl_parameter_new_enum("giraffe.extraction.method",
03572 CPL_TYPE_STRING,
03573 "Extraction method: 'SUM', 'HORNE' or "
03574 "'OPTIMAL'",
03575 "giraffe.extraction",
03576 "SUM", 3, "SUM", "OPTIMAL", "HORNE");
03577 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-method");
03578 cpl_parameterlist_append(list, p);
03579
03580
03581 p = cpl_parameter_new_value("giraffe.extraction.ron",
03582 CPL_TYPE_DOUBLE,
03583 "New bias sigma (RON) value for "
03584 "bias and dark "
03585 "corrected image",
03586 "giraffe.extraction",
03587 -1.);
03588 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-ron");
03589 cpl_parameterlist_append(list, p);
03590
03591
03592 p = cpl_parameter_new_enum("giraffe.extraction.psf.model",
03593 CPL_TYPE_STRING,
03594 "PSF profile model: `psfexp', `psfexp2'",
03595 "giraffe.extraction.psf",
03596 "psfexp2", 2, "psfexp", "psfexp2");
03597 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-psfmodel");
03598 cpl_parameterlist_append(list, p);
03599
03600
03601 p = cpl_parameter_new_value("giraffe.extraction.psf.sigma",
03602 CPL_TYPE_DOUBLE,
03603 "Sigma clippging threshold used for "
03604 "rejecting data points during PSF fitting "
03605 "(Horne's sigma). It is used to reject bad "
03606 "pixels and cosmics.",
03607 "giraffe.extraction.psf",
03608 7.);
03609 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-psfsigma");
03610 cpl_parameterlist_append(list, p);
03611
03612
03613 p = cpl_parameter_new_value("giraffe.extraction.psf.iterations",
03614 CPL_TYPE_INT,
03615 "Maximum number of iterations used for "
03616 "fitting the PSF profile.",
03617 "giraffe.extraction.psf",
03618 2);
03619 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-psfniter");
03620 cpl_parameterlist_append(list, p);
03621
03622
03623 p = cpl_parameter_new_value("giraffe.extraction.horne.extrawidth",
03624 CPL_TYPE_INT,
03625 "Horne extraction method: Number of "
03626 "extra pixels added to the fiber "
03627 "half-width.",
03628 "giraffe.extraction.horne",
03629 2);
03630 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-hewidth");
03631 cpl_parameterlist_append(list, p);
03632
03633
03634 p = cpl_parameter_new_value("giraffe.extraction.horne.mingood",
03635 CPL_TYPE_INT,
03636 "Horne extraction method: Minimum number of "
03637 "points used for the profile fit. It sets "
03638 "the lower limit of data points for the "
03639 "pixel rejection.",
03640 "giraffe.extraction.horne",
03641 3);
03642 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-hmingood");
03643 cpl_parameterlist_append(list, p);
03644
03645
03646 p = cpl_parameter_new_range("giraffe.extraction.optimal.fraction",
03647 CPL_TYPE_DOUBLE,
03648 "Optimal extraction method: Minimum fraction "
03649 "of the data points used for fitting the "
03650 "fiber profiles. It sets the lower limit "
03651 "for the pixel rejection.",
03652 "giraffe.extraction.optimal",
03653 0.9, 0.0, 1.0);
03654 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-omfrac");
03655 cpl_parameterlist_append(list, p);
03656
03657
03658 p = cpl_parameter_new_value("giraffe.extraction.optimal.wfactor",
03659 CPL_TYPE_DOUBLE,
03660 "Optimal extraction method: Factor by which "
03661 "the fiber PSF half width is multiplied. "
03662 "Adjacent spectra within this area are "
03663 "assumed to affect the spectrum being "
03664 "extracted.",
03665 "giraffe.extraction.optimal",
03666 3.);
03667 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-owfactor");
03668 cpl_parameterlist_append(list, p);
03669
03670
03671 p = cpl_parameter_new_value("giraffe.extraction.optimal.bkgorder",
03672 CPL_TYPE_INT,
03673 "Optimal extraction method: Order of the "
03674 "polynomial background model, which is "
03675 "fitted for each wavelength bin along the "
03676 "spatial direction.",
03677 "giraffe.extraction.optimal",
03678 2);
03679 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "extr-obkgorder");
03680 cpl_parameterlist_append(list, p);
03681
03682
03683 return;
03684
03685 }