GIRAFFE Pipeline Reference Manual

gifxcalibration.c

00001 /* $Id: gifxcalibration.c,v 1.4.2.1 2008/06/10 14:09:33 rpalsa Exp $
00002  *
00003  * This file is part of the GIRAFFE Pipeline
00004  * Copyright (C) 2002-2006 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 /*
00022  * $Author: rpalsa $
00023  * $Date: 2008/06/10 14:09:33 $
00024  * $Revision: 1.4.2.1 $
00025  * $Name: giraffe-2_5_3 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #  include <config.h>
00030 #endif
00031 
00032 
00033 #include <math.h>
00034 
00035 #include <cxmacros.h>
00036 #include <cxstrutils.h>
00037 
00038 #include <cpl_propertylist.h>
00039 #include <cpl_table.h>
00040 #include <cpl_msg.h>
00041 
00042 #include "gialias.h"
00043 #include "gierror.h"
00044 #include "gimessages.h"
00045 #include "giastroutils.h"
00046 #include "gifxcalibration.h"
00047 
00048 
00057 /*
00058  * @brief
00059  *   Compute the angular separation of two objects.
00060  *
00061  * @param ra_0   Rightascension of the first object in degrees.
00062  * @param dec_0  Declination of the first object in degrees.
00063  * @param ra_1   Rightascension of the second object in degrees.
00064  * @param dec_1  Declination of the second object in degrees.
00065  *
00066  * @return
00067  *   The angular separation of the two objects in arcsec.
00068  *
00069  * Computes the angular separation of the two coordinate pairs given.
00070  */
00071 
00072 inline static cxdouble
00073 _giraffe_compute_separation(cxdouble ra_0, cxdouble dec_0,
00074                             cxdouble ra_1, cxdouble dec_1)
00075 {
00076 
00077     const cxdouble deg2rad = CX_PI / 360.;
00078 
00079     cxdouble dist = 0.;
00080 
00081 
00082     ra_0 *= deg2rad;
00083     ra_1 *= deg2rad;
00084     dec_0 *= deg2rad;
00085     dec_1 *= deg2rad;
00086 
00087     dist = sin(dec_0) * sin(dec_1) +
00088             cos(dec_0) * cos(dec_1) * cos(ra_0 - ra_1);
00089 
00090     dist = CX_CLAMP(dist, -1., 1.);
00091     dist = acos(dist) / deg2rad * 3600.;
00092 
00093     return dist;
00094 
00095 }
00096 
00097 
00098 /*
00099  * @brief
00100  *  Spline interpolation using Hermite polynomials.
00101  *
00102  * @param xp      Abscissa value for which the interpolation is computed.
00103  * @param x       Array of abscissa values
00104  * @param y       Array of ordinate values
00105  * @param istart  Index of the first array element used.
00106  *
00107  * @return
00108  *  The interpolated value of the column @em ylabel.
00109  *
00110  * The function performs a spline interpolation using Hermite polynomials.
00111  * The array @em x and @em y provide the abscissa and ordinate values of
00112  * the function to be interpolated. The interpolation is computed for the
00113  * abscissa value @em xp.
00114  */
00115 
00116 inline static cxdouble
00117 _giraffe_spline_hermite(cxdouble xp, const cxdouble* x, const cxdouble* y,
00118                         cxint n, cxint* istart)
00119 {
00120 
00121     cxint i = 0;
00122 
00123     cxdouble yp = 0.;
00124     cxdouble yp1 = 0.;
00125     cxdouble yp2 = 0.;
00126     cxdouble xpi = 0.;
00127     cxdouble xpi1 = 0.;
00128     cxdouble l1 = 0.;
00129     cxdouble l2 = 0.;
00130     cxdouble lp1 = 0.;
00131     cxdouble lp2 = 0.;
00132 
00133 
00134     if ((x[0] <= x[n - 1]) && ((xp < x[0]) || (xp > x[n - 1]))) {
00135         return 0.;
00136     }
00137 
00138     if ((x[0] > x[n - 1]) && ((xp > x[0]) || (xp < x[n - 1]))) {
00139         return 0.;
00140     }
00141 
00142     if (x[0] <= x[n - 1]) {
00143 
00144         for (i = *istart + 1; i <= n && xp >= x[i - 1]; ++i) {
00145             ;
00146         }
00147 
00148     }
00149     else {
00150 
00151         for (i = *istart + 1; i <= n && xp <= x[i - 1]; ++i) {
00152             ;
00153         }
00154 
00155     }
00156 
00157     *istart = i;
00158     --i;
00159 
00160 
00161     lp1 = 1. / (x[i - 1] - x[i]);
00162     lp2 = -lp1;
00163 
00164     if (i == 1) {
00165         yp1 = (y[1] - y[0]) / (x[1] - x[0]);
00166     }
00167     else {
00168         yp1 = (y[i] - y[i - 2]) / (x[i] - x[i - 2]);
00169     }
00170 
00171     if (i >= n - 1) {
00172         yp2 = (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2]);
00173     }
00174     else {
00175         yp2 = (y[i + 1] - y[i - 1]) / (x[i + 1] - x[i - 1]);
00176     }
00177 
00178 
00179     xpi  = xp - x[i - 1];
00180     xpi1 = xp - x[i];
00181 
00182     l1 = xpi1 * lp1;
00183     l2 = xpi * lp2;
00184 
00185     yp = y[i - 1] * (1. - 2. * lp1 * xpi) * l1 * l1 +
00186             y[i] * (1. - 2. * lp2 * xpi1) * l2 * l2 +
00187             yp1 * xpi * l1 * l1 +
00188             yp2 * xpi1 * l2 * l2;
00189 
00190     return yp;
00191 
00192 }
00193 
00194 
00195 /*
00196  * @brief
00197  *  Spline interpolation of a table column.
00198  *
00199  * @param tbl     Table with column to interpolate
00200  * @param xlabel  Column label of the abscissa column
00201  * @param ylabel  Column label of the ordinate column
00202  * @param xp      Abscissa value for which the interpolation is computed.
00203  * @param istart  Row index of the first table row used.
00204  *
00205  * @return
00206  *  The interpolated value of the column @em ylabel.
00207  *
00208  * The function performs a spline interpolation using Hermite polynomials
00209  * of the table column given by the column label @em ylabel. The column
00210  * @em xlabel are the corresponding abscissa values, and @em xp is the
00211  * abscissa value for which the interpolation is computed.
00212  */
00213 
00214 inline static cxdouble
00215 _giraffe_interpolate_spline_hermite(const cpl_table* tbl,
00216                                     const cxchar* xlabel,
00217                                     const cxchar* ylabel,
00218                                     cxdouble xp, cxint* istart)
00219 {
00220 
00221     cxint n = cpl_table_get_nrow(tbl);
00222 
00223     const cxdouble* x = cpl_table_get_data_double_const(tbl, xlabel);
00224     const cxdouble* y = cpl_table_get_data_double_const(tbl, ylabel);
00225 
00226 
00227     return _giraffe_spline_hermite(xp, x, y, n ,istart);
00228 
00229 }
00230 
00231 
00232 /*
00233  * @brief
00234  *  Creates a 2d table of a flux standard star catalog spectrum
00235  *
00236  * @param catalog  3d table of flux standard reference spectra.
00237  * @param row      Table row from which the reference spectrum is extracted.
00238  *
00239  * @return
00240  *  The function returns a newly allocated 2d table containing the
00241  *  tabulated spectrum of the flux standard, or @c NULL if an error
00242  *  occurred.
00243  *
00244  * The input catalog @em catalog contains one flux standard spectrum per
00245  * table row. The function take a spectrum from the the given row @em row
00246  * and stores it in an ordinary table structures. The output table contains
00247  * 3 columns, which give the wavelength and the width of each wavelength bin,
00248  * and the reference flux at this wavelenght. The column names are
00249  * "LAMBDA", "BIN_WIDTH" and "F_LAMBDA" respectively.
00250  *
00251  * If the catalog contains wavelength in Angstrom, all 3 columns are
00252  * converted to nano meters.
00253  */
00254 
00255 inline static cpl_table*
00256 _giraffe_create_flux_table(const cpl_table* catalog, cxint row)
00257 {
00258 
00259     const cxchar* const _id = "_giraffe_create_flux_table";
00260 
00261 
00262     const cxchar* columns[] = {"LAMBDA", "BIN_WIDTH", "F_LAMBDA"};
00263     const cxchar* units = NULL;
00264 
00265     cxint ndata = cpl_table_get_int(catalog, "NDATA", row, NULL);
00266 
00267     cxsize i = 0;
00268 
00269     const cxdouble ang2nm = 0.1;  /* Conversion factor Angstroem to nm */
00270 
00271     cpl_table* flux = NULL;
00272 
00273 
00274 
00275     if (ndata <= 0) {
00276         return NULL;
00277     }
00278 
00279     giraffe_error_push();
00280 
00281     flux = cpl_table_new(ndata);
00282 
00283     for (i = 0; i < CX_N_ELEMENTS(columns); ++i) {
00284 
00285         const cpl_array* data = cpl_table_get_array(catalog, columns[i], row);
00286 
00287         cpl_type type = cpl_table_get_column_type(catalog, columns[i]);
00288 
00289 
00290         cpl_table_new_column(flux, columns[i], CPL_TYPE_DOUBLE);
00291 
00292         if ((data != NULL) && (ndata <= cpl_array_get_size(data))) {
00293 
00294             switch (type & ~CPL_TYPE_POINTER) {
00295                 case CPL_TYPE_FLOAT:
00296                 {
00297 
00298                     cxint j = 0;
00299 
00300                     register cxdouble value = 0.;
00301 
00302 
00303                     for (j = 0; j < ndata; ++j) {
00304                         value = cpl_array_get_float(data, j, NULL);
00305                         cpl_table_set_double(flux, columns[i], j, value);
00306                     }
00307 
00308                     break;
00309 
00310                 }
00311 
00312                 case CPL_TYPE_DOUBLE:
00313                 {
00314 
00315                     cxint j = 0;
00316 
00317                     register cxdouble value = 0.;
00318 
00319 
00320                     for (j = 0; j < ndata; ++j) {
00321                         value = cpl_array_get_double(data, j, NULL);
00322                         cpl_table_set_double(flux, columns[i], j, value);
00323                     }
00324 
00325                     break;
00326 
00327                 }
00328 
00329                 default:
00330                 {
00331                     cpl_error_set(_id, CPL_ERROR_INVALID_TYPE);
00332                     break;
00333 
00334                 }
00335             }
00336 
00337         }
00338 
00339     }
00340 
00341 
00342    /*
00343     * The fluxes of the catalog spectra are scaled by a factor of 1.e+16.
00344     * This scaling is reversed here.
00345     */
00346 
00347     cpl_table_multiply_scalar(flux, columns[2], 1.e-16);
00348 
00349 
00350     /*
00351      * If catalog wavelengths are given in terms of Angstrom all columns
00352      * are converted to nm, assuming that the catalog columns are consistent.
00353      * If no unit is given, or the unit string is empty, it is assumed that
00354      * the table data is already given in nm.
00355      */
00356 
00357     units = cpl_table_get_column_unit(catalog, columns[0]);
00358 
00359     if ((units != NULL) && (cx_strncasecmp(units, "ang", 3) == 0)) {
00360 
00361         cpl_msg_debug(_id, "Found units '%s'. Converting flux standard "
00362                       "from Angstrom to nano meters", units);
00363 
00364         cpl_table_multiply_scalar(flux, columns[0], ang2nm);
00365         cpl_table_set_column_unit(flux, columns[0], "nm");
00366 
00367         cpl_table_multiply_scalar(flux, columns[1], ang2nm);
00368         cpl_table_set_column_unit(flux, columns[1], "nm");
00369 
00370         cpl_table_divide_scalar(flux, columns[2], ang2nm);
00371         cpl_table_set_column_unit(flux, columns[2], "erg/s/cm^2/nm");
00372 
00373     }
00374     else {
00375 
00376         if (units == NULL) {
00377 
00378             cpl_msg_debug(_id, "No units for wavelength column. Assuming "
00379                           "nano meters.");
00380 
00381         }
00382         else {
00383 
00384             cpl_msg_debug(_id, "Found unknown units ('%s') for wavelength "
00385                     "column. Assuming nano meters.", units);
00386 
00387         }
00388 
00389     }
00390 
00391 
00392     if (cpl_error_get_code() != CPL_ERROR_NONE) {
00393         cpl_table_delete(flux);
00394         flux = NULL;
00395 
00396         return NULL;
00397     }
00398 
00399     giraffe_error_pop();
00400 
00401     return flux;
00402 
00403 }
00404 
00405 
00406 /*
00407  * @brief
00408  *  Create a standardized extinction table from input table.
00409  *
00410  * @param extinction  Input extinction table.
00411  *
00412  * @return
00413  *  The created standard extinction table, or @c NULL if an error occurred.
00414  *
00415  * The function creates a new extinction table from the input table. If the
00416  * input table contains wavelength in units of Angstroem the wavelength are
00417  * converted to nano meters. The column of the extinction coefficients to
00418  * use is copied from the input table and renamed to "EXTINCTION".
00419  */
00420 
00421 inline static cpl_table*
00422 _giraffe_setup_extinction(const cpl_table* extinction)
00423 {
00424 
00425     const cxchar* const _id = "_giraffe_setup_extinction";
00426 
00427     const cxchar* site = NULL;
00428     const cxchar* units = NULL;
00429     const cxchar* sites[] = {"PARANAL", "LA_SILLA", NULL};
00430 
00431     cxint i = 0;
00432     cxint rows = 0;
00433 
00434     const cxdouble ang2nm = 0.1;  /* Conversion factor Angstroem to nm */
00435 
00436     cxdouble scale = 1.;
00437 
00438     cpl_table* _extinction = NULL;
00439 
00440 
00441     if (cpl_table_has_column(extinction, "LAMBDA") == FALSE) {
00442 
00443         cpl_error_set(_id, CPL_ERROR_ILLEGAL_INPUT);
00444         return NULL;
00445 
00446     }
00447 
00448 
00449     /*
00450      * Convert wavelength units from Angstroem to nano meters
00451      */
00452 
00453     units = cpl_table_get_column_unit(extinction, "LAMBDA");
00454 
00455     if ((units != NULL) && (cx_strncasecmp(units, "ang", 3) == 0)) {
00456 
00457         scale = ang2nm;
00458 
00459         cpl_msg_debug(_id, "Found units '%s'. Converting wavelength"
00460                 "from Angstrom to nano meters", units);
00461 
00462     }
00463     else {
00464 
00465         if (units == NULL) {
00466 
00467             cpl_msg_debug(_id, "No units for wavelength column. "
00468                     "Assuming nano meters.");
00469 
00470         }
00471         else {
00472 
00473             if (cx_strncasecmp(units, "nm", 2) == 0) {
00474 
00475                 cpl_msg_debug(_id, "Found units nano meters ('%s') for "
00476                         "wavelength column.", units);
00477 
00478             }
00479             else {
00480 
00481                 cpl_msg_debug(_id, "Found unknown units ('%s') for "
00482                         "wavelength column. Assuming nano meters.", units);
00483 
00484             }
00485 
00486         }
00487 
00488     }
00489 
00490 
00491     /*
00492      * Select the extinction coefficients for the
00493      */
00494 
00495     while ((site == NULL) && (sites[i] != NULL)) {
00496 
00497         if (cpl_table_has_column(extinction, sites[i]) == TRUE) {
00498 
00499             site = sites[i];
00500             break;
00501 
00502         }
00503 
00504         ++i;
00505 
00506     }
00507 
00508     if (site == NULL) {
00509         cpl_msg_debug(_id, "No matching observatory site found!");
00510         return NULL;
00511     }
00512 
00513 
00514     /*
00515      * Setup the final extinction table
00516      */
00517 
00518     rows = cpl_table_get_nrow(extinction);
00519 
00520     giraffe_error_push();
00521 
00522     _extinction = cpl_table_new(rows);
00523     cpl_table_new_column(_extinction, "LAMBDA", CPL_TYPE_DOUBLE);
00524     cpl_table_set_column_unit(_extinction, "LAMBDA", "nm");
00525 
00526     cpl_table_new_column(_extinction, "EXTINCTION", CPL_TYPE_DOUBLE);
00527     cpl_table_set_column_unit(_extinction, "EXTINCTION", "mag/airmass");
00528 
00529     if (cpl_error_get_code() != CPL_ERROR_NONE) {
00530 
00531         cpl_table_delete(_extinction);
00532         _extinction = NULL;
00533 
00534         return NULL;
00535 
00536     }
00537 
00538     giraffe_error_pop();
00539 
00540 
00541     switch (cpl_table_get_column_type(extinction, "LAMBDA")) {
00542         case CPL_TYPE_FLOAT:
00543         {
00544             for (i = 0; i < rows; ++i) {
00545 
00546                 register cxdouble lambda = cpl_table_get_float(extinction,
00547                         "LAMBDA", i, NULL);
00548 
00549                 cpl_table_set_double(_extinction, "LAMBDA", i,
00550                                      scale * lambda);
00551 
00552             }
00553             break;
00554         }
00555 
00556         case CPL_TYPE_DOUBLE:
00557         {
00558             for (i = 0; i < rows; ++i) {
00559 
00560                 register cxdouble lambda = cpl_table_get_double(extinction,
00561                         "LAMBDA", i, NULL);
00562 
00563                 cpl_table_set_double(_extinction, "LAMBDA", i,
00564                                      scale * lambda);
00565 
00566             }
00567             break;
00568         }
00569 
00570         default:
00571         {
00572             cpl_table_delete(_extinction);
00573             _extinction = NULL;
00574 
00575             cpl_msg_debug(_id, "Column type (%d) is not supported for "
00576                     "extinction tables!",
00577                     cpl_table_get_column_type(extinction, "LAMBDA"));
00578 
00579             return NULL;
00580             break;
00581         }
00582     }
00583 
00584     switch (cpl_table_get_column_type(extinction, site)) {
00585         case CPL_TYPE_FLOAT:
00586         {
00587             for (i = 0; i < rows; ++i) {
00588 
00589                 register cxdouble aext = cpl_table_get_float(extinction,
00590                         site, i, NULL);
00591 
00592                 cpl_table_set_double(_extinction, "EXTINCTION", i, aext);
00593 
00594             }
00595             break;
00596         }
00597 
00598         case CPL_TYPE_DOUBLE:
00599         {
00600             for (i = 0; i < rows; ++i) {
00601 
00602                 register cxdouble aext = cpl_table_get_double(extinction,
00603                         site, i, NULL);
00604 
00605                 cpl_table_set_double(_extinction, "EXTINCTION", i, aext);
00606 
00607             }
00608             break;
00609         }
00610 
00611         default:
00612         {
00613             cpl_table_delete(_extinction);
00614             _extinction = NULL;
00615 
00616             cpl_msg_debug(_id, "Column type (%d) is not supported for "
00617                     "extinction tables!",
00618                     cpl_table_get_column_type(extinction, site));
00619 
00620             return NULL;
00621             break;
00622         }
00623     }
00624 
00625 
00626     return _extinction;
00627 
00628 }
00629 
00630 inline static cpl_image*
00631 _giraffe_compute_mean_sky(const cpl_image* spectra, const cpl_table* fibers)
00632 {
00633 
00634     cxint i = 0;
00635     cxint nsky = 0;
00636     cxint ns = cpl_image_get_size_x(spectra);
00637     cxint nw = cpl_image_get_size_y(spectra);
00638     cxint nr = cpl_table_get_nrow(fibers);
00639 
00640     const cxdouble* _spectra = cpl_image_get_data_double_const(spectra);
00641 
00642     cpl_image* sky = cpl_image_new(1, nw, CPL_TYPE_DOUBLE);
00643 
00644     cxdouble* _sky = cpl_image_get_data_double(sky);
00645 
00646 
00647     if (sky == NULL) {
00648         return NULL;
00649     }
00650 
00651 
00652     for (i = 0; i < nr; ++i) {
00653 
00654         const cxchar* s = cpl_table_get_string(fibers, "Retractor", i);
00655 
00656         if (strstr(s, "-Sky") != NULL) {
00657 
00658             register cxint j = cpl_table_get_int(fibers, "INDEX",
00659                     i, NULL) - 1;
00660             register cxint k = 0;
00661 
00662 
00663             for (k = 0; k < nw; ++k) {
00664                 _sky[k] += _spectra[k * ns + j];
00665             }
00666 
00667             ++nsky;
00668 
00669         }
00670 
00671     }
00672 
00673     if (nsky == 0) {
00674         cpl_image_delete(sky);
00675         sky = NULL;
00676     }
00677     else {
00678 
00679         cxint status = cpl_image_divide_scalar(sky, nsky);
00680 
00681         if (status != CPL_ERROR_NONE) {
00682             cpl_image_delete(sky);
00683             sky = NULL;
00684         }
00685 
00686     }
00687 
00688     return sky;
00689 
00690 }
00691 
00692 
00693 /*
00694  * @brief
00695  *   Correct a spectrum for the atmospheric extinction.
00696  *
00697  * @param spectrum    The spectrum to be corrected.
00698  * @param properties  Properties of the input spectrum.
00699  * @param extinction  The table containing the atmospheric extinction.
00700  *
00701  * @return
00702  *   The function returns 0 on success, or a non-zero value otherwise.
00703  *
00704  * The function corrects the input spectrum @em spectrum for the atmospheric
00705  * extinction. The atmospheric extinction as a function of wavelength is
00706  * taken from the table @em extinction.
00707  *
00708  * The extinction table is expected to contain a wavelength column "LAMBDA"
00709  * in units of nano meters. To support legacy tables "Angstroem" are
00710  * also accepted, but not recommended.
00711  */
00712 
00713 inline static cxint
00714 _giraffe_correct_extinction(cpl_image* spectrum, cpl_propertylist* properties,
00715                             const cpl_table* extinction)
00716 {
00717 
00718     const cxchar* const _id = "_giraffe_correct_extinction";
00719 
00720 
00721     cxint i = 0;
00722     cxint status = 0;
00723     cxint nw = 0;
00724 
00725     cxdouble alpha = 0.;
00726     cxdouble delta = 0.;
00727     cxdouble lst = 0.;
00728     cxdouble latitude = 0.;
00729     cxdouble exptime = 0.;
00730     cxdouble wlstart = 0.;
00731     cxdouble wlstep = 0.;
00732     cxdouble airmass = -1.;
00733     cxdouble* flx = NULL;
00734 
00735     cpl_table* _extinction = NULL;
00736 
00737 
00738     if ((spectrum == NULL) || (properties == NULL) || (extinction == NULL)) {
00739         return -1;
00740     }
00741 
00742 
00743     if (cpl_image_get_size_x(spectrum) != 1) {
00744 
00745         cpl_msg_debug(_id, "Input spectrum is not a 1d spectrum!");
00746         return -1;
00747 
00748     }
00749 
00750 
00751     /*
00752      * Setup the extinction table. This will convert wavelengths from
00753      * Angstroem to nano meters if it is necessary, and set the
00754      * name of the column of extinction coefficients to "Extinction".
00755      */
00756 
00757     _extinction = _giraffe_setup_extinction(extinction);
00758 
00759     if (_extinction == NULL) {
00760         return 1;
00761     }
00762 
00763 
00764     /*
00765      * Get the wavelength grid parameters of the observered spectrum
00766      */
00767 
00768     if ((cpl_propertylist_has(properties, GIALIAS_BINWLMIN) == FALSE) ||
00769          (cpl_propertylist_has(properties, GIALIAS_BINSTEP) == FALSE)) {
00770 
00771         cpl_msg_debug(_id, "Observed spectrum does not have a valid "
00772                 "wavelength grid!");
00773 
00774         cpl_table_delete(_extinction);
00775         _extinction = NULL;
00776 
00777         return 2;
00778 
00779     }
00780 
00781     wlstart = cpl_propertylist_get_double(properties, GIALIAS_BINWLMIN);
00782     wlstep = cpl_propertylist_get_double(properties, GIALIAS_BINSTEP);
00783 
00784 
00785     /*
00786      * Compute the airmass for the time of the observation
00787      */
00788 
00789     giraffe_error_push();
00790 
00791     alpha = cpl_propertylist_get_double(properties, GIALIAS_RADEG);
00792     delta = cpl_propertylist_get_double(properties, GIALIAS_DECDEG);
00793     lst = cpl_propertylist_get_double(properties, GIALIAS_LST);
00794     latitude = cpl_propertylist_get_double(properties, GIALIAS_TEL_LAT);
00795     exptime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
00796 
00797     status = cpl_error_get_code();
00798 
00799     if (status == CPL_ERROR_NONE) {
00800 
00801         airmass = giraffe_compute_airmass(alpha, delta, lst, exptime,
00802                                         latitude);
00803 
00804     }
00805 
00806     if ((airmass < 1.) || (status != CPL_ERROR_NONE)) {
00807 
00808         cxbool start = cpl_propertylist_has(properties,
00809                 GIALIAS_AIRMASS_START);
00810         cxbool end = cpl_propertylist_has(properties,
00811                                         GIALIAS_AIRMASS_END);
00812 
00813         if ((start == FALSE) || (end == FALSE)) {
00814 
00815             cpl_msg_debug(_id, "Unable to compute airmass of the "
00816                     "observation!");
00817 
00818             cpl_table_delete(_extinction);
00819             _extinction = NULL;
00820 
00821             return 3;
00822 
00823         }
00824         else {
00825 
00826             airmass = 0.5 * (cpl_propertylist_get_double(properties,
00827                             GIALIAS_AIRMASS_START) +
00828                     cpl_propertylist_get_double(properties,
00829                                     GIALIAS_AIRMASS_END));
00830 
00831         }
00832 
00833     }
00834 
00835     giraffe_error_pop();
00836 
00837 
00838     /*
00839      * Apply the correction to the input spectrum
00840      */
00841 
00842     nw = cpl_image_get_size_y(spectrum);
00843     flx = cpl_image_get_data_double(spectrum);
00844 
00845     for (i = 0; i < nw; ++i) {
00846 
00847         cxint first = 0;
00848 
00849         cxdouble wlen = wlstart + (i - 1) * wlstep;
00850         cxdouble ext = 1.;
00851 
00852 
00853         giraffe_error_push();
00854 
00855         ext = _giraffe_interpolate_spline_hermite(_extinction,
00856                 "LAMBDA", "EXTINCTION", wlen, &first);
00857 
00858         if (cpl_error_get_code() != CPL_ERROR_NONE) {
00859 
00860             cpl_table_delete(_extinction);
00861             _extinction = NULL;
00862 
00863             return 3;
00864 
00865         }
00866 
00867         giraffe_error_pop();
00868 
00869 
00870         /*
00871          * Correct the spectrum flux of this wavelength bin for
00872          * atmospheric extinction.
00873          *
00874          * The extinction ext is given in mag/airmass. The correction for
00875          * the effect of the earth atmoshpere gives for the observed
00876          * magnitude at the top of the atmosphere m_top = m - ext * airmass
00877          *
00878          * Converting the magnitude into a flux using m = -2.5 * log10(flux)
00879          * the correction factor to be applied is 10^(0.4 * ext * airmass)
00880          */
00881 
00882         flx[i] *= pow(10., 0.4 * ext * airmass);
00883 
00884     }
00885 
00886     cpl_table_delete(_extinction);
00887     _extinction = NULL;
00888 
00889     return 0;
00890 
00891 }
00892 
00893 
00894 /*
00895  * @brief
00896  *   Compute the instrument spectral response function.
00897  *
00898  * @param spectrum    Observed flux standard spectrum image.
00899  * @param properties  Properties of the observed flux standard.
00900  * @param refflux     Reference fluxes of the flux standard.
00901  *
00902  * @return
00903  *   On success the function returns the instruments spectral response
00904  *   function as an image, or @c NULL otherwise.
00905  *
00906  * The instruments spectral response function is computed, by interpolating
00907  * the tabulated reference flux of the observed flux standard onto the
00908  * wavelength grid of the observed spectrum, and dividing the observed
00909  * flux by the reference flux values.
00910  */
00911 
00912 inline static cpl_image*
00913 _giraffe_compute_response(const cpl_image* spectrum,
00914                           const cpl_propertylist* properties,
00915                           const cpl_table* refflux)
00916 {
00917 
00918     const cxchar* const _id = "giraffe_compute_response";
00919 
00920 
00921     cxint i = 0;
00922     cxint nw = 0;
00923 
00924     const cxdouble* flx = NULL;
00925 
00926     cxdouble wlstart = 0.;
00927     cxdouble wlstep = 0.;
00928     cxdouble* rdata = NULL;
00929 
00930 
00931     cpl_image* response = NULL;
00932 
00933 
00934 
00935     if ((spectrum == NULL) || (properties == NULL) || (refflux == NULL)) {
00936         return NULL;
00937     }
00938 
00939     if (cpl_image_get_size_x(spectrum) != 1) {
00940 
00941         cpl_msg_debug(_id, "Observed spectrum is not a 1d spectrum!");
00942         return NULL;
00943 
00944     }
00945 
00946 
00947     /*
00948      * Get the wavelength grid parameters of the observered spectrum
00949      */
00950 
00951     if ((cpl_propertylist_has(properties, GIALIAS_BINWLMIN) == FALSE) ||
00952         (cpl_propertylist_has(properties, GIALIAS_BINSTEP) == FALSE)) {
00953 
00954         cpl_msg_debug(_id, "Observed spectrum does not have a valid "
00955                       "wavelength grid!");
00956         return NULL;
00957 
00958     }
00959 
00960     wlstart = cpl_propertylist_get_double(properties, GIALIAS_BINWLMIN);
00961     wlstep = cpl_propertylist_get_double(properties, GIALIAS_BINSTEP);
00962 
00963     nw = cpl_image_get_size_y(spectrum);
00964 
00965 
00966     /*
00967      * Compute the response for each spectrum and wavelength bin of the
00968      * observed spectrum image.
00969      */
00970 
00971     flx = cpl_image_get_data_double_const(spectrum);
00972 
00973     response = cpl_image_new(1, nw, CPL_TYPE_DOUBLE);
00974     rdata = cpl_image_get_data_double(response);
00975 
00976     for (i = 0; i < nw; ++i) {
00977 
00978         cxint first = 0;
00979 
00980         cxdouble wlen = wlstart + (i - 1) * wlstep;
00981         cxdouble sflx = 0.;
00982 
00983 
00984         giraffe_error_push();
00985 
00986         sflx = _giraffe_interpolate_spline_hermite(refflux,
00987                 "LAMBDA", "F_LAMBDA", wlen, &first);
00988 
00989         if (cpl_error_get_code() != CPL_ERROR_NONE) {
00990 
00991             cpl_image_delete(response);
00992             response = NULL;
00993 
00994             return NULL;
00995 
00996         }
00997 
00998         giraffe_error_pop();
00999 
01000         rdata[i] = flx[i] / sflx;
01001 
01002     }
01003 
01004     return response;
01005 
01006 }
01007 
01008 
01009 GiTable*
01010 giraffe_select_flux_standard(const GiTable* catalog, const GiImage* spectra,
01011                              cxdouble max_dist)
01012 {
01013 
01014     const cxchar* const _id = "giraffe_select_flux_standard";
01015 
01016     cxint row = 0;
01017     cxint nmatch = 0;
01018 
01019     cxdouble ra = 0.;
01020     cxdouble dec = 0.;
01021     cxdouble std_ra = 0.;
01022     cxdouble std_dec = 0.;
01023     cxdouble min_dist = 0.;
01024 
01025     const cpl_table* _catalog = NULL;
01026 
01027     cpl_table* _flux = NULL;
01028 
01029     const cpl_propertylist* properties = NULL;
01030 
01031     GiTable* flux = NULL;
01032 
01033 
01034     if ((catalog == NULL) || (spectra == NULL)) {
01035         return NULL;
01036     }
01037 
01038     _catalog = giraffe_table_get(catalog);
01039     cx_assert(_catalog != NULL);
01040 
01041 
01042     /*
01043     * Get the telescope pointing from the properties of the
01044     * rebinned spectra
01045     */
01046 
01047     properties = giraffe_image_get_properties(spectra);
01048     cx_assert(properties != NULL);
01049 
01050     giraffe_error_push();
01051 
01052     ra = cpl_propertylist_get_double(properties, GIALIAS_RADEG);
01053     dec = cpl_propertylist_get_double(properties, GIALIAS_DECDEG);
01054 
01055     if (cpl_error_get_code() != CPL_ERROR_NONE) {
01056         return NULL;
01057     }
01058 
01059     giraffe_error_pop();
01060 
01061 
01062     /*
01063      * Search for matching objects in the flux standards catalog
01064      */
01065 
01066     cpl_msg_debug(_id, "Searching flux standard by name...");
01067 
01068     if ((cpl_propertylist_has(properties, GIALIAS_TARGET) == TRUE) &&
01069         (cpl_table_has_column(_catalog, "OBJECT") == TRUE)) {
01070 
01071         const cxchar* target = cpl_propertylist_get_string(properties,
01072                 GIALIAS_TARGET);
01073 
01074 
01075         if ((target != NULL) && (target[0] != '\0')) {
01076 
01077             register cxint i = 0;
01078 
01079 
01080             for (i = 0; i < cpl_table_get_nrow(_catalog); ++i) {
01081 
01082                 const cxchar* object = cpl_table_get_string(_catalog,
01083                         "OBJECT", i);
01084 
01085 
01086                 if (strcmp(target, object) == 0) {
01087 
01088                     cxdouble cat_ra = cpl_table_get_double(_catalog,
01089                             "RA_DEG", i, NULL);
01090                     cxdouble cat_dec = cpl_table_get_double(_catalog,
01091                             "DEC_DEG", i, NULL);
01092 
01093 
01094                     std_ra = cpl_table_get_double(_catalog,
01095                             "RA_DEG", i, NULL);
01096                     std_dec = cpl_table_get_double(_catalog,
01097                             "DEC_DEG", i, NULL);
01098 
01099                     min_dist = _giraffe_compute_separation(ra, dec,
01100                             cat_ra, cat_dec);
01101 
01102                     row = i;
01103                     ++nmatch;
01104 
01105                 }
01106 
01107             }
01108 
01109         }
01110 
01111     }
01112 
01113     cpl_msg_debug(_id, "%d flux standards found...", nmatch);
01114 
01115 
01116     if (nmatch == 0) {
01117 
01118         cxint i = 0;
01119 
01120 
01121         cpl_msg_debug(_id, "Searching flux standard by coordinates...");
01122 
01123         if ((cpl_table_has_column(_catalog, "RA_DEG") == FALSE) ||
01124             (cpl_table_has_column(_catalog, "DEC_DEG") == FALSE)) {
01125 
01126             cpl_error_set(_id, CPL_ERROR_DATA_NOT_FOUND);
01127 
01128             return NULL;
01129 
01130         }
01131 
01132 
01133         for (i = 0; i < cpl_table_get_nrow(_catalog); ++i) {
01134 
01135             cxdouble cat_ra = cpl_table_get_double(_catalog, "RA_DEG",
01136                     i, NULL);
01137             cxdouble cat_dec = cpl_table_get_double(_catalog, "DEC_DEG",
01138                     i, NULL);
01139 
01140             cxdouble dist = 0.;
01141 
01142 
01143             /*
01144              * Compute angular separation between the observation and the
01145              * positions given in the flux standards catalog.
01146              */
01147 
01148             dist = _giraffe_compute_separation(ra, dec, cat_ra, cat_dec);
01149 
01150             if ((i == 0) || (dist < min_dist)) {
01151 
01152                 std_ra = cat_ra;
01153                 std_dec = cat_dec;
01154                 min_dist = dist;
01155 
01156                 if (dist < max_dist) {
01157                     ++nmatch;
01158                     row = i;
01159                 }
01160 
01161             }
01162 
01163         }
01164 
01165         cpl_msg_debug(_id, "%d flux standards found...", nmatch);
01166 
01167     }
01168 
01169 
01170     switch (nmatch) {
01171 
01172         case 0:
01173         {
01174 
01175             const cxchar* object = cpl_table_get_string(_catalog,
01176                     "OBJECT", row);
01177 
01178             cpl_msg_debug(_id, "No flux standard found within %.4f arcsec",
01179                           max_dist);
01180             cpl_msg_debug(_id, "The closest object ('%s') at (RA, Dec) = "
01181                           "(%.4f, %.4f) is %.4f arcsec away", object, std_ra,
01182                           std_dec, min_dist);
01183 
01184             cpl_error_set(_id, CPL_ERROR_INCOMPATIBLE_INPUT);
01185 
01186             return NULL;
01187             break;
01188 
01189         }
01190 
01191         case 1:
01192         {
01193 
01194             const cxchar* object = cpl_table_get_string(_catalog,
01195                     "OBJECT", row);
01196 
01197             cpl_msg_debug(_id, "Flux standard ('%s') at (RA, Dec) = "
01198                           "(%.4f, %.4f) found at a distance of %.4f arcsec",
01199                           object, std_ra, std_dec, min_dist);
01200 
01201             /*
01202              * Create flux table of the flux standart object found.
01203              */
01204 
01205             _flux = _giraffe_create_flux_table(_catalog, row);
01206 
01207             break;
01208 
01209         }
01210 
01211         default:
01212         {
01213 
01214             const cxchar* object = cpl_table_get_string(_catalog,
01215                     "OBJECT", row);
01216 
01217             cpl_msg_debug(_id, "%d flux standards found within %.4f arcsec",
01218                           nmatch, max_dist);
01219             cpl_msg_debug(_id, "The closest object ('%s') at (RA, Dec) = "
01220                           "(%.4f, %.4f) is %.4f arcsec away", object, std_ra,
01221                           std_dec, min_dist);
01222 
01223             cpl_error_set(_id, CPL_ERROR_INCOMPATIBLE_INPUT);
01224 
01225             return NULL;
01226             break;
01227 
01228         }
01229 
01230     }
01231 
01232     if (_flux != NULL) {
01233 
01234         flux = giraffe_table_new();
01235         giraffe_table_set(flux, _flux);
01236 
01237     }
01238 
01239     //FIXME: Remove test output!
01240     //cpl_table_save(_flux, NULL, NULL, "stdcat.fits", CPL_IO_DEFAULT);
01241 
01242     cpl_table_delete(_flux);
01243     _flux = NULL;
01244 
01245     return flux;
01246 
01247 }
01248 
01249 
01291 cxint
01292 giraffe_calibrate_flux(GiResponse* result, const GiRebinning* spectra,
01293                        const GiTable* fibers, const GiImage* flat,
01294                        const GiTable* flux, const GiTable* extinction,
01295                        const GiFxCalibrationConfig* config)
01296 {
01297 
01298     const cxchar* const _id = "giraffe_calibrate_flux";
01299 
01300 
01301     const cxint xrad = 7;
01302     const cxint yrad = 0;
01303 
01304     const cxdouble UT_M1_VIGNETTED_AREA = 517533.407382;  /* cm^2    */
01305     const cxdouble H_PLANCK = 6.62606896e-27;             /* erg s   */
01306     const cxdouble C_LIGHT = 2.99792458e17;               /* nm s^-1 */
01307 
01308     cxint i = 0;
01309     cxint status = 0;
01310     cxint nw = 0;
01311     cxint ns = 0;
01312 
01313     const cxdouble* rdata = NULL;
01314 
01315     cxdouble conad = 0.;
01316     cxdouble wlstep = 0.;
01317     cxdouble wlstart = 0.;
01318     cxdouble exptime = 0.;
01319     cxdouble scale = UT_M1_VIGNETTED_AREA / (H_PLANCK * C_LIGHT);
01320 
01321     cpl_propertylist* properties = NULL;
01322 
01323     cpl_matrix* filter = NULL;
01324 
01325     cpl_image* _spectra = NULL;
01326     cpl_image* fluxobs = NULL;
01327     cpl_image* response = NULL;
01328     cpl_image* fresponse = NULL;
01329 
01330     cpl_table* _extinction = NULL;
01331     cpl_table* _flux = NULL;
01332     cpl_table* efficiency = NULL;
01333 
01334 
01335     if (result == NULL) {
01336         return -1;
01337     }
01338 
01339     if ((spectra == NULL) || (spectra->spectra == NULL)) {
01340         return -2;
01341     }
01342 
01343     if (fibers == NULL) {
01344         return -3;
01345     }
01346 
01347     if ((flux == NULL) || (extinction == NULL)) {
01348         return -4;
01349     }
01350 
01351     if (config == NULL) {
01352         return -5;
01353     }
01354 
01355 
01356     if ((result->response != NULL) || (result->efficiency != NULL)) {
01357 
01358         gi_warning("%s: Results structure at %p is not empty! Contents "
01359                 "might be lost.", _id, result);
01360 
01361     }
01362 
01363     properties = giraffe_image_get_properties(spectra->spectra);
01364     cx_assert(properties != NULL);
01365 
01366     _spectra = giraffe_image_get(spectra->spectra);
01367     cx_assert(_spectra != NULL);
01368 
01369     _extinction = giraffe_table_get(extinction);
01370     cx_assert(_extinction != NULL);
01371 
01372     _flux = giraffe_table_get(flux);
01373     cx_assert(_flux != NULL);
01374 
01375 
01376 
01377     /*
01378      * Compute the total observed flux. No background subtraction is
01379      * performed, but it is assumed that the background is negligible.
01380      * Also, no attempt is made to figure out which fibers actually
01381      * were illuminated by the object.
01382      */
01383 
01384     fluxobs = cpl_image_collapse_create(_spectra, 1);
01385 
01386 
01387     //FIXME: Remove test output!
01388     //cpl_image_save(fluxobs, "fluxraw.fits", CPL_BPP_IEEE_FLOAT, NULL,
01389     //               CPL_IO_DEFAULT);
01390 
01391     if (config->sky_subtraction == TRUE) {
01392 
01393         cpl_image* sky_spectrum = NULL;
01394 
01395         cpl_table* _fibers = giraffe_table_get(fibers);
01396 
01397 
01398         ns = cpl_image_get_size_x(_spectra);
01399 
01400         sky_spectrum = _giraffe_compute_mean_sky(_spectra, _fibers);
01401 
01402         if (sky_spectrum == NULL) {
01403 
01404             cpl_image_delete(fluxobs);
01405             fluxobs = NULL;
01406 
01407             return 1;
01408 
01409         }
01410 
01411         // FIXME: Remove test output!
01412         //cpl_image_save(sky_spectrum, "sky.fits", CPL_BPP_IEEE_FLOAT, NULL,
01413         //               CPL_IO_DEFAULT);
01414 
01415 
01416         giraffe_error_push();
01417         
01418         /*
01419          * Scale the sky spectrum by the number of used fibers fibers,
01420          * including the sky fibers themselves, since they were not
01421          * ignored when the total flux was computed.
01422          */
01423 
01424         // FIXME: This is not really correct, since it ignores the
01425         //        differences in the fiber transmission. This needs to
01426         //        be taken into account!
01427 
01428         cpl_image_multiply_scalar(sky_spectrum, ns);
01429 
01430 
01431         /*
01432          * Subtract the sky spectrum
01433          */
01434 
01435         cpl_image_subtract(fluxobs, sky_spectrum);
01436 
01437         cpl_image_delete(sky_spectrum);
01438         sky_spectrum = NULL;
01439         
01440         if (cpl_error_get_code() != CPL_ERROR_NONE) {
01441 
01442             cpl_image_delete(fluxobs);
01443             fluxobs = NULL;
01444 
01445             return 1;
01446 
01447         }
01448         
01449         giraffe_error_pop();
01450 
01451     }
01452 
01453 
01454     //FIXME: Remove test output!
01455     //cpl_image_save(fluxobs, "fluxsky.fits", CPL_BPP_IEEE_FLOAT, NULL,
01456     //               CPL_IO_DEFAULT);
01457 
01458     /*
01459      * Correct for the atmospheric extinction
01460      */
01461 
01462     status = _giraffe_correct_extinction(fluxobs, properties, _extinction);
01463 
01464     if (status != 0) {
01465         cpl_msg_warning(_id, "Extinction correction failed!");
01466     }
01467 
01468     //FIXME: Remove test output!
01469     //cpl_image_save(fluxobs, "fluxext.fits", CPL_BPP_IEEE_FLOAT, NULL,
01470     //               CPL_IO_DEFAULT);
01471 
01472 
01473     exptime = cpl_propertylist_get_double(properties, GIALIAS_EXPTIME);
01474     conad = cpl_propertylist_get_double(properties, GIALIAS_CONAD);
01475     wlstep = cpl_propertylist_get_double(properties, GIALIAS_BINSTEP);
01476     wlstart = cpl_propertylist_get_double(properties, GIALIAS_BINWLMIN);
01477 
01478 
01479     /*
01480      * Convert the observed spectrum from ADU to e- / s / nm
01481      */
01482 
01483     cpl_image_multiply_scalar(fluxobs, conad / exptime / wlstep);
01484 
01485     //FIXME: Remove test output!
01486     //cpl_image_save(fluxobs, "fluxscl.fits", CPL_BPP_IEEE_FLOAT, NULL,
01487     //               CPL_IO_DEFAULT);
01488 
01489 
01490     /*
01491      * Compute the response function R = Fobs / Fref in units of
01492      * 'e- erg^-1 cm^2'
01493      */
01494 
01495     response = _giraffe_compute_response(fluxobs, properties, _flux);
01496 
01497     cpl_image_delete(fluxobs);
01498     fluxobs = NULL;
01499 
01500     if (response == NULL) {
01501         return 2;
01502     }
01503 
01504     //FIXME: Remove test output!
01505     //cpl_image_save(response, "rspraw.fits", CPL_BPP_IEEE_FLOAT, NULL,
01506     //               CPL_IO_DEFAULT);
01507 
01508 
01509     filter = cpl_matrix_new(2 * xrad + 1, 2 * yrad + 1);
01510     cpl_matrix_fill(filter, 1.);
01511 
01512     fresponse = cpl_image_filter_median(response, filter);
01513 
01514     cpl_matrix_delete(filter);
01515     filter = NULL;
01516 
01517     cpl_image_delete(response);
01518     response = fresponse;
01519 
01520     if (response == NULL) {
01521         return 3;
01522     }
01523 
01524     //FIXME: Remove test output!
01525     //cpl_image_save(response, "rspmed.fits", CPL_BPP_IEEE_FLOAT, NULL,
01526     //               CPL_IO_DEFAULT);
01527 
01528 
01529     /*
01530     * Compute instrument efficiency
01531     */
01532 
01533 
01534     giraffe_error_push();
01535 
01536     nw = cpl_image_get_size_y(response);
01537 
01538     efficiency = cpl_table_new(nw);
01539 
01540     cpl_table_new_column(efficiency, "WLEN", CPL_TYPE_DOUBLE);
01541     cpl_table_new_column(efficiency, "BINWIDTH", CPL_TYPE_DOUBLE);
01542     cpl_table_new_column(efficiency, "EFFICIENCY", CPL_TYPE_DOUBLE);
01543 
01544     cpl_table_set_column_unit(efficiency, "WLEN", "nm");
01545     cpl_table_set_column_unit(efficiency, "BINWIDTH", "nm");
01546 
01547     if (cpl_error_get_code() != CPL_ERROR_NONE) {
01548 
01549         cpl_table_delete(efficiency);
01550         efficiency = NULL;
01551 
01552         cpl_image_delete(response);
01553         response = NULL;
01554 
01555         return 4;
01556 
01557     }
01558 
01559     giraffe_error_pop();
01560 
01561 
01562     rdata = cpl_image_get_data_double_const(response);
01563 
01564     for (i = 0; i < nw; ++i) {
01565 
01566         cxdouble wl = wlstart + i * wlstep;
01567 
01568         cpl_table_set_double(efficiency, "WLEN", i, wl);
01569         cpl_table_set_double(efficiency, "BINWIDTH", i, wlstep);
01570         cpl_table_set_double(efficiency, "EFFICIENCY", i,
01571                              rdata[i] / (scale * wl));
01572 
01573     }
01574 
01575     rdata = NULL;
01576 
01577 
01578     /*
01579      * Fill the results object
01580      */
01581 
01582 
01583     result->response = giraffe_image_new(CPL_TYPE_DOUBLE);
01584     giraffe_image_set_properties(result->response, properties);
01585     giraffe_image_set(result->response, response);
01586 
01587     cpl_image_delete(response);
01588     response = NULL;
01589 
01590     result->efficiency = giraffe_table_new();
01591     giraffe_table_set_properties(result->efficiency, properties);
01592     giraffe_table_set(result->efficiency, efficiency);
01593 
01594     cpl_table_delete(efficiency);
01595     efficiency = NULL;
01596 
01597     return 0;
01598 
01599 }
01600 
01601 
01602 GiFxCalibrationConfig*
01603 giraffe_fxcalibration_config_create(cpl_parameterlist* parameters)
01604 {
01605     
01606     cpl_parameter *p = NULL;
01607     
01608     GiFxCalibrationConfig* self = NULL;
01609     
01610     
01611     if (parameters == NULL) {
01612         return NULL;
01613     }
01614     
01615     self = cx_calloc(1, sizeof *self);
01616     cx_assert(self != NULL);
01617     
01618     
01619     /*
01620      * Set application defaults
01621      */
01622     
01623     self->sky_subtraction = FALSE;
01624     
01625     /*
01626      * Lookup the parameters in the given parameter list and set the
01627      * value accordingly if it is found.
01628      */
01629     
01630     p = cpl_parameterlist_find(parameters,
01631             "giraffe.fxcalibration.sky.correct");
01632     
01633     if (p != NULL) {
01634         self->sky_subtraction = cpl_parameter_get_bool(p);
01635     }
01636 
01637     return self;
01638     
01639 }
01640 
01641 
01655 void
01656 giraffe_fxcalibration_config_destroy(GiFxCalibrationConfig* self)
01657 {
01658 
01659     if (self != NULL) {
01660         cx_free(self);
01661     }
01662     
01663     return;
01664     
01665 }
01666 
01667 
01681 void
01682 giraffe_fxcalibration_config_add(cpl_parameterlist* parameters)
01683 {
01684     
01685     cpl_parameter* p = NULL;
01686     
01687     
01688     if (parameters == NULL) {
01689         return;
01690     }
01691     
01692     p = cpl_parameter_new_value("giraffe.fxcalibration.sky.correct",
01693                                 CPL_TYPE_BOOL,
01694                                 "Correct spectra for the sky emission",
01695                                 "giraffe.fxcalibration",
01696                                 FALSE);
01697     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flx-skycorr");
01698     cpl_parameterlist_append(parameters, p);
01699 
01700     return;
01701 
01702 }

This file is part of the GIRAFFE Pipeline Reference Manual 2.5.3.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Fri Jul 18 09:49:46 2008 by doxygen 1.4.6 written by Dimitri van Heesch, © 1997-2004