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