KMOS Pipeline Reference Manual  1.3.11
kmos_std_star.c
00001 /* 
00002  * This file is part of the KMOS Pipeline
00003  * Copyright (C) 2002,2003 European Southern Observatory
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023 
00024 /*-----------------------------------------------------------------------------
00025  *                              Includes
00026  *----------------------------------------------------------------------------*/
00027 
00028 #include <math.h>
00029 #include <string.h>
00030 
00031 #include <cpl.h>
00032 
00033 #include "kmclipm_math.h"
00034 
00035 #include "kmo_constants.h"
00036 #include "kmo_cpl_extensions.h"
00037 #include "kmo_utils.h"
00038 #include "kmo_functions.h"
00039 #include "kmo_priv_std_star.h"
00040 #include "kmo_priv_fit_profile.h"
00041 #include "kmo_priv_extract_spec.h"
00042 #include "kmo_priv_functions.h"
00043 #include "kmo_dfs.h"
00044 #include "kmo_error.h"
00045 #include "kmo_debug.h"
00046 #include "kmo_priv_reconstruct.h"
00047 
00048 const int       nr_lines_h = 10;
00049 const double    lines_center_h[] = {
00050     1.7001,     // HeI          // triplet
00051     1.53429,    // Br-18
00052     1.54400,    // Br-17
00053     1.55576,    // Br-16
00054     1.57018,    // Br-15
00055     1.58817,    // Br-14
00056     1.61105,    // Br-13
00057     1.64084,    // Br-12
00058     1.68077,    // Br-11
00059     1.73634     // Br-10
00060 };
00061 const double    lines_width_h[] = {
00062     0.025,      // HeI
00063     0.003,      // Br-18
00064     0.015,      // Br-17
00065     0.015,      // Br-16
00066     0.015,      // Br-15
00067     0.025,      // Br-14
00068     0.015,      // Br-13
00069     0.025,      // Br-12
00070     0.025,      // Br-11
00071     0.05        // Br-10
00072 };
00073 const int       nr_lines_k = 2;
00074 const double    lines_center_k[] = {
00075     2.1120,     // HeI          // triplet
00076     2.16569     // Br-gamma
00077 };
00078 const double lines_width_k[] = {
00079     0.01,       // HeI          // triplet
00080     0.015       // Br-gamma
00081 };
00082 const int       nr_lines_hk = 12;
00083 const double    lines_center_hk[] = {
00084     1.7001,     // HeI          // triplet
00085     1.53429,    // Br-18
00086     1.54400,    // Br-17
00087     1.55576,    // Br-16
00088     1.57018,    // Br-15
00089     1.58817,    // Br-14
00090     1.61105,    // Br-13
00091     1.64084,    // Br-12
00092     1.68077,    // Br-11
00093     1.73634,    // Br-10
00094     2.1120,     // HeI          // triplet
00095     2.16569     // Br-gamma
00096 };
00097 const double lines_width_hk[] = {
00098     0.025,      // HeI
00099     0.003,      // Br-18
00100     0.015,      // Br-17
00101     0.015,      // Br-16
00102     0.015,      // Br-15
00103     0.025,      // Br-14
00104     0.015,      // Br-13
00105     0.025,      // Br-12
00106     0.025,      // Br-11
00107     0.05,       // Br-10
00108     0.015,      // HeI          // triplet
00109     0.015       // Br-gamma
00110 };
00111 const int       nr_lines_iz = 12;
00112 const double    lines_center_iz[] = {
00113     0.84386,    // Pa-18
00114     0.84679,    // Pa-17
00115     0.85031,    // Pa-16
00116     0.85460,    // Pa-15
00117     0.85990,    // Pa-14
00118     0.86657,    // Pa-13
00119     0.87511,    // Pa-12
00120     0.88635,    // Pa-11
00121     0.90156,    // Pa-10
00122     0.92297,    // Pa-9
00123     0.95467,    // Pa-epsilon
00124     1.00501     // Pa-delta
00125 };
00126 const double    lines_width_iz[] = {
00127     0.0008,     // Pa-18
00128     0.003225,   // Pa-17
00129     0.0039,     // Pa-16
00130     0.0048,     // Pa-15
00131     0.006,      // Pa-14
00132     0.0076,     // Pa-13
00133     0.001,      // Pa-12
00134     0.013,      // Pa-11
00135     0.01,       // Pa-10
00136     0.013,      // Pa-9
00137     0.02,       // Pa-epsilon
00138     0.025       // Pa-delta
00139 };
00140 const int       nr_lines_yj = 7;
00141 const double    lines_center_yj[] = {
00142     1.08331,    // HeI
00143     1.09160,    // HeI
00144     1.09389,    // Pa-gamma
00145     1.19723,    // HeI
00146     1.28191,    // Pa-beta
00147     1.27882,    // HeI
00148     1.29720     // HeI
00149 };
00150 const double    lines_width_yj[] = {
00151     .01,        //0.005,    // HeI
00152     .01,        //0.002,    // HeI
00153     0.02,       // Pa-gamma
00154     0.003,      // HeI
00155     0.02,       // Pa-beta
00156     0.0025,     // HeI
00157     0.002       // HeI
00158 };
00159 
00160 /*-----------------------------------------------------------------------------
00161  *                          Functions prototypes
00162  *----------------------------------------------------------------------------*/
00163 
00164 static int kmos_std_star_compute_ifu(
00165         cpl_propertylist    *   sub_header_orig,
00166         cpl_frame           *   obj_frame,
00167         cpl_frame           *   sky_frame,
00168         cpl_frame           *   flat_frame,
00169         cpl_frame           *   xcal_frame,
00170         cpl_frame           *   ycal_frame,
00171         cpl_frame           *   lcal_frame,
00172         cpl_frame           *   illum_frame,
00173         cpl_frame           *   atmos_frame,
00174         cpl_frame           *   solar_frame,
00175         int                     ifu_nr,
00176         cpl_propertylist    *   main_header_tel,
00177         gridDefinition          gd,
00178         int                     low_bound,
00179         int                     high_bound,
00180         const char          *   fmethod,
00181         int                     flux,
00182         int                     xcal_interpolation,
00183         const char          *   cmethod,
00184         double                  cpos_rej,
00185         double                  cneg_rej,
00186         int                     citer,
00187         int                     cmax,
00188         int                     cmin,
00189         const char          *   filter_id,
00190         char                    star_type,
00191         int                     no_noise,
00192         int                     is_stdstarscipatt,
00193         skySkyStruct            sky_sky_struct,
00194         double                  star_temp,
00195         cpl_vector          **  spec_qc,
00196         cpl_propertylist    **  out_sub_tel_data_header,
00197         cpl_propertylist    **  out_sub_psf_header,
00198         cpl_propertylist    **  out_sub_cube_data_header,
00199         cpl_imagelist       **  out_data_cube,
00200         cpl_imagelist       **  out_noise_cube,
00201         cpl_image           **  out_psf_data,
00202         cpl_image           **  out_mask,
00203         cpl_vector          **  out_starspec_data,
00204         cpl_vector          **  out_starspec_noise,
00205         cpl_vector          **  out_noisespec,
00206         cpl_vector          **  out_telluric_data,
00207         cpl_vector          **  out_telluric_noise) ;
00208 static int kmos_std_star_check_inputs(
00209         cpl_frameset            *   frameset,
00210         const char              *   magnitude_txt,
00211         int                     *   is_stdstarscipatt,
00212         int                     *   compute_qcs,
00213         double                  *   magnitude1,
00214         double                  *   magnitude2) ;
00215 static int kmos_std_star_plot(void) ;
00216 static int kmos_std_star_adjust_double(
00217         cpl_propertylist    *   header,
00218         const char          *   key1,
00219         const char          *   key2,
00220         const char          *   key3) ;
00221 static int kmos_std_star_adjust_string(
00222         cpl_propertylist    *   header,
00223         const char          *   key1,
00224         const char          *   key2,
00225         const char          *   key3) ;
00226 static cpl_frameset * kmos_std_star_extract_same_grat_stds(
00227         cpl_frameset        *   in,
00228         int                 *   same_gratings) ;
00229 
00230 static int kmos_std_star_create(cpl_plugin *);
00231 static int kmos_std_star_exec(cpl_plugin *);
00232 static int kmos_std_star_destroy(cpl_plugin *);
00233 static int kmos_std_star(cpl_parameterlist *, cpl_frameset *);
00234 
00235 /*-----------------------------------------------------------------------------
00236  *                          Static variables
00237  *----------------------------------------------------------------------------*/
00238 
00239 static char kmos_std_star_description[] =
00240 "This recipe creates a telluric frame and a PSF frames.\n"
00241 "Since there cannot be 1 std star per IFU in one exposure, we use several\n"
00242 "exposures in order to have at least one standard star and one sky\n"
00243 "in each IFU. The frames are organised following this logic:\n"
00244 "1. For each IFU the first standard star in the list of frames is\n"
00245 "   taken. All subsequent standard star exposures for this IFU are ignored\n"
00246 "2. A closest in time sky exposure is uѕed\n"
00247 "3. IFUs not containing a standard star and a sky will be empty in the result\n"
00248 "\n"
00249 "NOISE_SPEC contains the shot noise [sqrt(counts*gain)/gain]\n"
00250 "If the exposures have been taken with KMOS_spec_cal_stdstarscipatt, an\n"
00251 "additional noise component is added: All existing sky exposures for an IFU\n"
00252 "are subtracted pairwise, spectra are extracted and the std deviation is \n"
00253 "computed\n"
00254 "\n"
00255 "-------------------------------------------------------------------------------\n"
00256 "  Input files:\n"
00257 "\n"
00258 "   DO                      KMOS                                             \n"
00259 "   category                Type  Explanation                Required #Frames\n"
00260 "   --------                ----- -----------                -------- -------\n"
00261 "   STD                     RAW   Std. star & sky exposures      Y     >=1   \n"
00262 "   XCAL                    F2D   x calibration frame            Y      1    \n"
00263 "   YCAL                    F2D   y calibration frame            Y      1    \n"
00264 "   LCAL                    F2D   Wavelength calib. frame        Y      1    \n"
00265 "   MASTER_FLAT             F2D   Master flat frame              Y      1    \n"
00266 "   WAVE_BAND               F2L   Table with start-/end-wl       Y      1    \n"
00267 "   ILLUM_CORR              F2I   Illumination correction        N     0,1   \n"
00268 "   SOLAR_SPEC              F1S   Solar spectrum                 N     0,1   \n"
00269 "                                 (only for G stars)                         \n"
00270 "   ATMOS_MODEL             F1S   Model atmospheric transmisson  N     0,1   \n"
00271 "                                 (only for OBAF stars in K band)            \n"
00272 "   SPEC_TYPE_LOOKUP        F2L   LUT  eff. stellar temperature  N     0,1   \n"
00273 "\n"
00274 "  Output files:                                                            \n"
00275 "\n"
00276 "   DO                      KMOS                                            \n"
00277 "   category                Type   Explanation                              \n"
00278 "   --------                -----  -----------                              \n"
00279 "   TELLURIC                F1I    The normalised telluric spectrum         \n"
00280 "                                  (including errors)                       \n"
00281 "   STAR_SPEC               F1I    The extracted star spectrum              \n"
00282 "                                  (including errors)                       \n"
00283 "   STD_IMAGE               F2I    The standard star PSF images             \n"
00284 "   STD_MASK                F2I    The mask used to extract the star spec   \n"
00285 "   NOISE_SPEC              F1I    The extracted noise spectrum             \n"
00286 "---------------------------------------------------------------------------\n"
00287 "\n";
00288 
00289 /*-----------------------------------------------------------------------------
00290  *                              Functions code
00291  *----------------------------------------------------------------------------*/
00292 
00293 /*----------------------------------------------------------------------------*/
00297 /*----------------------------------------------------------------------------*/
00298 
00301 /*----------------------------------------------------------------------------*/
00310 /*----------------------------------------------------------------------------*/
00311 int cpl_plugin_get_info(cpl_pluginlist *list)
00312 {
00313     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00314     cpl_plugin *plugin = &recipe->interface;
00315 
00316     cpl_plugin_init(plugin,
00317             CPL_PLUGIN_API,
00318             KMOS_BINARY_VERSION,
00319             CPL_PLUGIN_TYPE_RECIPE,
00320             "kmos_std_star",
00321             "Create the telluric correction frame.",
00322             kmos_std_star_description,
00323             "Alex Agudo Berbel, Y. Jung",
00324             "usd-help@eso.org",
00325             kmos_get_license(),
00326             kmos_std_star_create,
00327             kmos_std_star_exec,
00328             kmos_std_star_destroy);
00329     cpl_pluginlist_append(list, plugin);
00330 
00331     return 0;
00332 }
00333 
00334 /*----------------------------------------------------------------------------*/
00342 /*----------------------------------------------------------------------------*/
00343 static int kmos_std_star_create(cpl_plugin *plugin)
00344 {
00345     cpl_recipe *recipe;
00346     cpl_parameter *p;
00347 
00348     /* Check that the plugin is part of a valid recipe */
00349     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00350         recipe = (cpl_recipe *)plugin;
00351     else
00352         return -1;
00353 
00354     /* Create the parameters list in the cpl_recipe object */
00355     recipe->parameters = cpl_parameterlist_new();
00356 
00357     /* --startype */
00358     p = cpl_parameter_new_value("kmos.kmos_std_star.startype", CPL_TYPE_STRING,
00359             "The spectral type of the star (O, B, A, F, G) e.g. G4V",
00360             "kmos.kmos_std_star", "");
00361     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startype");
00362     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00363     cpl_parameterlist_append(recipe->parameters, p);
00364 
00365     /* --imethod */
00366     p = cpl_parameter_new_value("kmos.kmos_std_star.imethod", CPL_TYPE_STRING,
00367             "Method to use for interpolation. "
00368             "[\"NN\" (nearest neighbour), "
00369             "\"lwNN\" (linear weighted nearest neighbor), "
00370             "\"swNN\" (square weighted nearest neighbor), "
00371             "\"MS\" (Modified Shepard's method), "
00372             "\"CS\" (Cubic spline)]",
00373             "kmos.kmos_std_star", "CS");
00374     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
00375     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00376     cpl_parameterlist_append(recipe->parameters, p);
00377 
00378     /* --fmethod */
00379     p = cpl_parameter_new_value("kmos.kmos_std_star.fmethod", CPL_TYPE_STRING,
00380             "Fitting method (gauss, moffat, profile", "kmos.kmos_std_star",
00381             "gauss");
00382     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fmethod");
00383     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00384     cpl_parameterlist_append(recipe->parameters, p);
00385 
00386     /* --neighborhoodRange */
00387     p = cpl_parameter_new_value("kmos.kmos_std_star.neighborhoodRange",
00388             CPL_TYPE_DOUBLE,
00389             "Defines the range to search for neighbors in pixels",
00390             "kmos.kmos_std_star", 1.001);
00391     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "neighborhoodRange");
00392     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00393     cpl_parameterlist_append(recipe->parameters, p);
00394 
00395     /* --magnitude */
00396     p = cpl_parameter_new_value("kmos.kmos_std_star.magnitude", CPL_TYPE_STRING,
00397             "Star magnitude (2 values in HK, eg. 12.1,13.2)",
00398             "kmos.kmos_std_star", "");
00399     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "magnitude");
00400     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00401     cpl_parameterlist_append(recipe->parameters, p);
00402 
00403     /* --flux */
00404     p = cpl_parameter_new_value("kmos.kmos_std_star.flux", CPL_TYPE_BOOL,
00405             "TRUE: Apply flux conservation. FALSE: otherwise",
00406             "kmos.kmos_std_star", TRUE);
00407     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "flux");
00408     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00409     cpl_parameterlist_append(recipe->parameters, p);
00410 
00411     /* --save_cubes */
00412     p = cpl_parameter_new_value("kmos.kmos_std_star.save_cubes", CPL_TYPE_BOOL,
00413             "Flag to save reconstructed cubes", "kmos.kmos_std_star", FALSE);
00414     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "save_cubes");
00415     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00416     cpl_parameterlist_append(recipe->parameters, p);
00417 
00418     /* --no_noise */
00419     p = cpl_parameter_new_value("kmos.kmos_std_star.no_noise", CPL_TYPE_BOOL,
00420             "Skip the noise computation on sky exposures", "kmos.kmos_std_star",
00421             FALSE);
00422     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "no_noise");
00423     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00424     cpl_parameterlist_append(recipe->parameters, p);
00425 
00426     /* --xcal_interpolation */
00427     p = cpl_parameter_new_value("kmos.kmos_std_star.xcal_interpolation",
00428             CPL_TYPE_BOOL, "Flag to Interpolate xcal between rotator angles",
00429             "kmos.kmos_std_star", TRUE);
00430     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "xcal_interpolation");
00431     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00432     cpl_parameterlist_append(recipe->parameters, p);
00433 
00434     /* --suppress_extension */
00435     p = cpl_parameter_new_value("kmos.kmos_std_star.suppress_extension",
00436             CPL_TYPE_BOOL, "Flag to Suppress filename extension",
00437             "kmos.kmos_std_star", FALSE);
00438     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension");
00439     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00440     cpl_parameterlist_append(recipe->parameters, p);
00441 
00442     /* Add parameters for band-definition */
00443     kmos_band_pars_create(recipe->parameters, "kmos.kmos_std_star");
00444 
00445     /* Add parameters for combining */
00446     return kmos_combine_pars_create(recipe->parameters, "kmos.kmos_std_star",
00447             DEF_REJ_METHOD, FALSE);
00448 }
00449 
00450 /*----------------------------------------------------------------------------*/
00456 /*----------------------------------------------------------------------------*/
00457 static int kmos_std_star_exec(cpl_plugin *plugin)
00458 {
00459     cpl_recipe  *recipe;
00460 
00461     /* Get the recipe out of the plugin */
00462     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00463         recipe = (cpl_recipe *)plugin;
00464     else return -1;
00465 
00466     return kmos_std_star(recipe->parameters, recipe->frames);
00467 }
00468 
00469 /*----------------------------------------------------------------------------*/
00475 /*----------------------------------------------------------------------------*/
00476 static int kmos_std_star_destroy(cpl_plugin *plugin)
00477 {
00478     cpl_recipe *recipe;
00479 
00480     /* Get the recipe out of the plugin */
00481     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00482         recipe = (cpl_recipe *)plugin;
00483     else return -1 ;
00484 
00485     cpl_parameterlist_delete(recipe->parameters);
00486     return 0 ;
00487 }
00488 
00489 /*----------------------------------------------------------------------------*/
00502 /*----------------------------------------------------------------------------*/
00503 static int kmos_std_star(cpl_parameterlist *parlist, cpl_frameset *frameset)
00504 {
00505     const cpl_parameter *   par ;
00506     /*********************/
00507     /* Parsed Parameters */
00508     const char          *   imethod ;        
00509     const char          *   cmethod ;        
00510     const char          *   fmethod ;        
00511     const char          *   spec_type ;        
00512     const char          *   magnitude_txt ;        
00513     double                  cpos_rej, cneg_rej, neighborhoodRange ;
00514     int                     flux, save_cubes, no_noise, citer, cmin, cmax,
00515                             xcal_interpolation, suppress_extension ;
00516     /*********************/
00517     char                *   suffix ;
00518     char                *   keyword ;
00519     char                *   extname ;
00520     char                *   fn_suffix ;
00521     const char          *   filter_id ;
00522     cpl_array           **  unused_ifus_before ;
00523     cpl_array           **  unused_ifus_after ;
00524     const int           *   punused_ifus ;
00525     gridDefinition          gd;
00526     cpl_propertylist    *   tmp_header ;
00527     cpl_propertylist    *   main_header_tel ;
00528     cpl_propertylist    *   sub_header_orig ;
00529     cpl_propertylist    *   main_header_psf ;
00530     int                 *   bounds ;
00531     objSkyStruct        *   obj_sky_struct ;
00532     skySkyStruct        *   sky_sky_struct ;
00533 
00534     cpl_imagelist       **  stored_data_cube ;
00535     cpl_imagelist       **  stored_noise_cube ;
00536     cpl_image           **  stored_psf_data ;
00537     cpl_image           **  stored_mask ;
00538     cpl_vector          **  stored_telluric_data ;
00539     cpl_vector          **  stored_telluric_noise ;
00540     cpl_vector          **  stored_starspec_data ;
00541     cpl_vector          **  stored_starspec_noise ;
00542     cpl_vector          **  stored_noisespec ;
00543     double              *   stored_qc_throughput ;
00544     cpl_propertylist    **  stored_sub_tel_data_headers ;
00545     cpl_propertylist    **  stored_sub_tel_noise_headers ;
00546     cpl_propertylist    **  stored_sub_cube_data_headers ;
00547     cpl_propertylist    **  stored_sub_cube_noise_headers ;
00548     cpl_propertylist    **  stored_sub_psf_headers ;
00549     char                    filename_telluric[256],
00550                             filename_starspec[256],
00551                             filename_psf[256],
00552                             filename_mask[256],
00553                             filename_cubes[256],
00554                             filename_noise[256] ;
00555     cpl_frame           *   obj_frame ;
00556     cpl_frame           *   sky_frame ;
00557     cpl_frame           *   xcal_frame ;
00558     cpl_frame           *   ycal_frame ;
00559     cpl_frame           *   lcal_frame ;
00560     cpl_frame           *   flat_frame ;
00561     cpl_frame           *   illum_frame ;
00562     cpl_frame           *   solar_frame ;
00563     cpl_frame           *   atmos_frame ;
00564     cpl_table           *   band_table ;
00565     cpl_frameset        *   frameset_std ;
00566     cpl_vector          *   spec_qc ;
00567     int                     is_stdstarscipatt, compute_qcs,
00568                             ifu_nr, nifus, nr_std_stars ;
00569     double                  magnitude1, magnitude2, star_temp, exptime, 
00570                             throughput_mean, throughput_sdv, cdelt1, crpix1, 
00571                             crval1, zeropoint, tmp_data, tmp_noise, counts1, 
00572                             counts2, gain ;
00573     char                    star_type ;
00574     kmclipm_vector      *   ddd  ;
00575     int                     i, j ;
00576     
00577     /* Initialise */
00578     nr_std_stars = 0 ;
00579     zeropoint = throughput_mean = throughput_sdv = -1.0 ;
00580     magnitude1 = magnitude2 = -1.0 ;
00581 
00582     /* Check entries */
00583     if (parlist == NULL || frameset == NULL) {
00584         cpl_msg_error(__func__, "Null Inputs") ;
00585         cpl_error_set(__func__, CPL_ERROR_NULL_INPUT) ;
00586         return -1 ;
00587     }
00588 
00589     /* Get parameters */
00590     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_std_star.imethod");
00591     imethod = cpl_parameter_get_string(par) ;
00592     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_std_star.startype");
00593     spec_type = cpl_parameter_get_string(par) ;
00594     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_std_star.fmethod");
00595     fmethod = cpl_parameter_get_string(par) ;
00596     par = cpl_parameterlist_find_const(parlist,
00597             "kmos.kmos_std_star.neighborhoodRange");
00598     neighborhoodRange = cpl_parameter_get_double(par) ;
00599     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_std_star.magnitude");
00600     magnitude_txt = cpl_parameter_get_string(par) ;
00601     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_std_star.flux");
00602     flux = cpl_parameter_get_bool(par);
00603     par = cpl_parameterlist_find_const(parlist,"kmos.kmos_std_star.save_cubes");
00604     save_cubes = cpl_parameter_get_bool(par);
00605     par = cpl_parameterlist_find_const(parlist, "kmos.kmos_std_star.no_noise");
00606     no_noise = cpl_parameter_get_bool(par);
00607     par = cpl_parameterlist_find_const(parlist,
00608         "kmos.kmos_std_star.xcal_interpolation");
00609     xcal_interpolation = cpl_parameter_get_bool(par);
00610     par = cpl_parameterlist_find_const(parlist,
00611         "kmos.kmos_std_star.suppress_extension");
00612     suppress_extension = cpl_parameter_get_bool(par);
00613     kmos_band_pars_load(parlist, "kmos.kmos_std_star");
00614     kmos_combine_pars_load(parlist, "kmos.kmos_std_star", &cmethod, &cpos_rej,
00615             &cneg_rej, &citer, &cmin, &cmax, FALSE);
00616 
00617     /* Check Parameters */
00618     if (strcmp(cmethod, "average") && strcmp(cmethod, "median") &&
00619             strcmp(cmethod, "sum") && strcmp(cmethod, "min_max") &&
00620             strcmp(cmethod, "ksigma")) {
00621         cpl_msg_error(__func__, 
00622                 "cmethod must be average median sum min_max or ksigma") ;
00623         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00624         return -1 ;
00625     }
00626     if (strcmp(imethod, "NN") && strcmp(imethod, "lwNN") &&
00627             strcmp(imethod, "swNN") && strcmp(imethod, "MS") &&
00628             strcmp(imethod, "CS")) {
00629         cpl_msg_error(__func__, "imethod must be NN,lwNN,swNN,MS or CS") ;
00630         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00631         return -1 ;
00632     }
00633     if (strcmp(fmethod, "gauss") && strcmp(fmethod, "moffat")) {
00634         cpl_msg_error(__func__, "fmethod must be gauss or moffat") ;
00635         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00636         return -1 ;
00637     }
00638     if (neighborhoodRange <= 0.0) {
00639         cpl_msg_error(__func__, "neighborhoodRange must be greater than 0.0") ;
00640         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00641         return -1 ;
00642     }
00643 
00644     /* Identify the RAW and CALIB frames in the input frameset */
00645     if (kmo_dfs_set_groups(frameset, "kmos_std_star") != 1) {
00646         cpl_msg_error(__func__, "Cannot identify RAW and CALIB frames") ;
00647         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00648         return -1 ;
00649     }
00650 
00651     /* Check the inputs consistency */
00652     if (kmos_std_star_check_inputs(frameset, magnitude_txt, &is_stdstarscipatt,
00653                 &compute_qcs, &magnitude1, &magnitude2) != 1) {
00654         cpl_msg_error(__func__, "Input frameset is not consistent") ;
00655         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00656         return -1 ;
00657     }
00658     
00659     /* Instrument setup */
00660     suffix = kmo_dfs_get_suffix(kmo_dfs_get_frame(frameset, STD), TRUE, FALSE);
00661     cpl_msg_info("", "Detected instrument setup:   %s", suffix+1);
00662 
00663     /* Check which IFUs are active for all frames */
00664     unused_ifus_before = kmo_get_unused_ifus(frameset, 0, 0);
00665     unused_ifus_after = kmo_duplicate_unused_ifus(unused_ifus_before);
00666     kmo_print_unused_ifus(unused_ifus_before, FALSE);
00667     kmo_free_unused_ifus(unused_ifus_before);
00668 
00669     /* Setup grid definition, wavelength start and end are set later */
00670     kmclipm_setup_grid(&gd, imethod, neighborhoodRange, KMOS_PIX_RESOLUTION,0.);
00671 
00672     /* Get left and right bounds of IFUs from XCAL */
00673     tmp_header = kmo_dfs_load_primary_header(frameset, XCAL);
00674     bounds = kmclipm_extract_bounds(tmp_header);
00675     cpl_propertylist_delete(tmp_header);
00676 
00677     /* Extract STD frames */
00678     frameset_std = kmos_std_star_extract_same_grat_stds(frameset, &i) ;
00679 
00680     /* Get valid STD frames with objects in it and associated sky exposures */
00681     obj_sky_struct = kmo_create_objSkyStruct(frameset_std, STD, FALSE);
00682     kmo_print_objSkyStruct(obj_sky_struct);
00683 
00684     /* Check if there is at least 1 object  */
00685     if (obj_sky_struct->size == 0) {
00686         cpl_free(suffix); 
00687         cpl_free(bounds); 
00688         kmo_free_unused_ifus(unused_ifus_after);
00689         cpl_frameset_delete(frameset_std) ;
00690         cpl_msg_error(cpl_func, "No Object found");
00691         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
00692         return -1 ;
00693     }
00694 
00695     /* Identify sky-sky-pairs for NOISE_SPEC calculation */
00696     sky_sky_struct = kmo_create_skySkyStruct(frameset_std);
00697 
00698     /* Get frame */
00699     illum_frame = kmo_dfs_get_frame(frameset, ILLUM_CORR);
00700     flat_frame = kmo_dfs_get_frame(frameset, MASTER_FLAT);
00701     xcal_frame = kmo_dfs_get_frame(frameset, XCAL) ;
00702     ycal_frame = kmo_dfs_get_frame(frameset, YCAL) ;
00703     lcal_frame = kmo_dfs_get_frame(frameset, LCAL) ;
00704     atmos_frame = kmo_dfs_get_frame(frameset, ATMOS_MODEL);
00705     solar_frame = kmo_dfs_get_frame(frameset, SOLAR_SPEC);
00706 
00707     /* Allocate intermediate memory */
00708     nifus = KMOS_NR_DETECTORS * KMOS_IFUS_PER_DETECTOR ;
00709     stored_telluric_data = (cpl_vector**)cpl_calloc(nifus, sizeof(cpl_vector*));
00710     stored_telluric_noise = (cpl_vector**)cpl_calloc(nifus,sizeof(cpl_vector*));
00711     stored_starspec_data = (cpl_vector**)cpl_calloc(nifus, sizeof(cpl_vector*));
00712     stored_starspec_noise = (cpl_vector**)cpl_calloc(nifus,sizeof(cpl_vector*));
00713     stored_psf_data = (cpl_image**)cpl_calloc(nifus, sizeof(cpl_image*));
00714     stored_mask = (cpl_image**)cpl_calloc(nifus, sizeof(cpl_image*));
00715     stored_data_cube =(cpl_imagelist**)cpl_calloc(nifus,sizeof(cpl_imagelist*));
00716     stored_noise_cube=(cpl_imagelist**)cpl_calloc(nifus,sizeof(cpl_imagelist*));
00717     stored_qc_throughput = (double*)cpl_calloc(nifus, sizeof(double));
00718     stored_sub_psf_headers = (cpl_propertylist**)cpl_calloc(nifus, 
00719             sizeof(cpl_propertylist*));
00720     stored_sub_tel_data_headers = (cpl_propertylist**)cpl_calloc(nifus, 
00721             sizeof(cpl_propertylist*));
00722     stored_sub_tel_noise_headers = (cpl_propertylist**)cpl_calloc(nifus, 
00723             sizeof(cpl_propertylist*));
00724     stored_sub_cube_data_headers = (cpl_propertylist**)cpl_calloc(nifus, 
00725             sizeof(cpl_propertylist*));
00726     stored_sub_cube_noise_headers=(cpl_propertylist**)cpl_calloc(nifus, 
00727             sizeof(cpl_propertylist*));
00728     stored_noisespec = (cpl_vector**)cpl_calloc(nifus, sizeof(cpl_vector*));
00729 
00730     strcpy(filename_telluric, TELLURIC);
00731     strcpy(filename_starspec, STAR_SPEC);
00732     strcpy(filename_psf, STD_IMAGE);
00733     strcpy(filename_mask, STD_MASK);
00734     strcpy(filename_cubes, STD_CUBE);
00735     strcpy(filename_noise, NOISE_SPEC);
00736 
00737     /*
00738     cpl_free(stored_telluric_data);
00739     cpl_free(stored_telluric_noise);
00740     cpl_free(stored_starspec_data);
00741     cpl_free(stored_starspec_noise); 
00742     cpl_free(stored_psf_data);
00743     cpl_free(stored_sub_tel_data_headers);
00744     cpl_free(stored_sub_tel_noise_headers);
00745     cpl_free(stored_noisespec);
00746     cpl_free(stored_sub_cube_data_headers);
00747     cpl_free(stored_sub_cube_noise_headers);
00748     cpl_free(stored_sub_psf_headers);
00749     cpl_free(stored_mask);
00750     cpl_free(stored_data_cube);
00751     cpl_free(stored_noise_cube);
00752     cpl_free(stored_qc_throughput) ;
00753     kmo_delete_objSkyStruct(obj_sky_struct);
00754     kmo_delete_skySkyStruct(sky_sky_struct);
00755     cpl_free(suffix); 
00756     cpl_free(bounds); 
00757     kmo_free_unused_ifus(unused_ifus_after);
00758     cpl_frameset_delete(frameset_std) ;
00759     return 0 ;
00760 */
00761     /* Get the first frame containing object */
00762     obj_frame = obj_sky_struct->table[0].objFrame;
00763     main_header_tel = kmclipm_propertylist_load(
00764             cpl_frame_get_filename(obj_frame), 0);
00765     exptime = cpl_propertylist_get_double(main_header_tel, EXPTIME);
00766 
00767     /* Get the star temperature */
00768     star_temp = kmos_get_temperature(frameset, spec_type, &star_type) ; 
00769 
00770     /* Loop on detectors */
00771     for (i = 1; i <= KMOS_NR_DETECTORS ; i++) {
00772         print_cal_angle_msg_once = FALSE;
00773         print_xcal_angle_msg_once = FALSE;
00774         if (i==1) {
00775             print_cal_angle_msg_once = TRUE;
00776             print_xcal_angle_msg_once = TRUE;
00777         }
00778 
00779         /* Get filter for this detector ESO INS FILTi ID */
00780         keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, i, 
00781                 IFU_FILTID_POSTFIX);
00782         filter_id = cpl_propertylist_get_string(main_header_tel, keyword);
00783         cpl_free(keyword);
00784 
00785         band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, 0);
00786         kmclipm_setup_grid_band_lcal(&gd, filter_id, band_table);
00787         cpl_table_delete(band_table); 
00788 
00789         /* Load extension header */
00790         sub_header_orig = kmclipm_propertylist_load(
00791                 cpl_frame_get_filename(obj_frame), i);
00792 
00793         /* Loop on IFUs */
00794         for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
00795             ifu_nr = (i-1)*KMOS_IFUS_PER_DETECTOR + j + 1;
00796 
00797             /* Check if IFU valid  */
00798 
00799             /* Check if there is a sky frame available for this IFU */
00800             kmo_collapse_objSkyStruct(obj_sky_struct, ifu_nr, &obj_frame,
00801                     &sky_frame);
00802             punused_ifus = cpl_array_get_data_int_const(unused_ifus_after[i-1]);
00803             /* Search for keyword ESO OCS ARMi NOTUSED */
00804             /* If CPL_ERROR_DATA_NOT_FOUND, process standard star */
00805             keyword = cpl_sprintf("%s%d%s", IFU_VALID_PREFIX, ifu_nr, 
00806                     IFU_VALID_POSTFIX);
00807             cpl_propertylist_get_string(main_header_tel, keyword);
00808             cpl_free(keyword);
00809 
00810             if ((cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) &&
00811                 (bounds[2*(ifu_nr-1)] != -1) &&
00812                 (bounds[2*(ifu_nr-1)+1] != -1) &&
00813                 (sky_frame != NULL) && (punused_ifus[j] == 0)) {
00814                 cpl_error_reset();
00815                 /* IFU is valid */
00816 
00817                 /* Process IFU */
00818                 if (kmos_std_star_compute_ifu(sub_header_orig, obj_frame, 
00819                             sky_frame, flat_frame, xcal_frame, ycal_frame, 
00820                             lcal_frame, illum_frame, atmos_frame, solar_frame, 
00821                             ifu_nr, main_header_tel, gd, bounds[2*(ifu_nr-1)], 
00822                             bounds[2*(ifu_nr-1)+1], fmethod, flux, 
00823                             xcal_interpolation, cmethod, cpos_rej, cneg_rej, 
00824                             citer, cmax, cmin, filter_id, star_type, no_noise, 
00825                             is_stdstarscipatt, sky_sky_struct[ifu_nr-1], 
00826                             star_temp, 
00827                             &spec_qc,
00828                             &stored_sub_tel_data_headers[ifu_nr-1],
00829                             &stored_sub_psf_headers[ifu_nr-1],
00830                             &stored_sub_cube_data_headers[ifu_nr-1],
00831                             &stored_data_cube[ifu_nr-1], 
00832                             &stored_noise_cube[ifu_nr-1],
00833                             &stored_psf_data[ifu_nr-1],
00834                             &stored_mask[ifu_nr-1],
00835                             &stored_starspec_data[ifu_nr-1],
00836                             &stored_starspec_noise[ifu_nr-1],
00837                             &stored_noisespec[ifu_nr-1],
00838                             &stored_telluric_data[ifu_nr-1],
00839                             &stored_telluric_noise[ifu_nr-1]) == -1) {
00840                     stored_telluric_data[ifu_nr-1] = NULL ;
00841                     stored_telluric_noise[ifu_nr-1] = NULL ;
00842                     stored_starspec_data[ifu_nr-1] = NULL ;
00843                     stored_starspec_noise[ifu_nr-1] = NULL ;
00844                     stored_psf_data[ifu_nr-1] = NULL ;
00845                     stored_mask[ifu_nr-1] = NULL ;
00846                     stored_data_cube[ifu_nr-1] = NULL ;
00847                     stored_noise_cube[ifu_nr-1] = NULL ;
00848                     stored_noisespec[ifu_nr-1] = NULL ;
00849 
00850                     stored_sub_tel_data_headers[ifu_nr-1] =
00851                         cpl_propertylist_duplicate(sub_header_orig);
00852                     stored_sub_tel_noise_headers[ifu_nr-1] =
00853                         cpl_propertylist_duplicate(sub_header_orig);
00854                     stored_sub_psf_headers[ifu_nr-1] =
00855                         cpl_propertylist_duplicate(sub_header_orig);
00856                     stored_sub_cube_data_headers[ifu_nr-1] =
00857                         cpl_propertylist_duplicate(sub_header_orig);
00858                     stored_sub_cube_noise_headers[ifu_nr-1] =
00859                         cpl_propertylist_duplicate(sub_header_orig);
00860                 } else {
00861                     /* If magnitude is provided, get zeropoint and throughput */
00862                     if (compute_qcs) {
00863                         /* QC THROUGHPUT */
00864                         gain = cpl_propertylist_get_double(
00865                                 stored_sub_tel_data_headers[ifu_nr-1], GAIN);
00866                         crpix1=cpl_propertylist_get_double(
00867                                 stored_sub_tel_data_headers[ifu_nr-1], CRPIX1);
00868                         crval1=cpl_propertylist_get_double(
00869                                 stored_sub_tel_data_headers[ifu_nr-1], CRVAL1);
00870                         cdelt1=cpl_propertylist_get_double(
00871                                 stored_sub_tel_data_headers[ifu_nr-1], CDELT1);
00872                         kmo_calc_counts(spec_qc, filter_id, crpix1, crval1, 
00873                                 cdelt1, &counts1, &counts2);
00874                         counts1 /= exptime;
00875                         counts2 /= exptime;
00876                         stored_qc_throughput[ifu_nr-1] = 
00877                             kmo_calc_throughput(magnitude1, magnitude2,
00878                                     counts1, counts2, gain, filter_id);
00879                         if (kmclipm_is_nan_or_inf(
00880                                     stored_qc_throughput[ifu_nr-1])) 
00881                             stored_qc_throughput[ifu_nr-1] = -1;
00882                         kmclipm_update_property_double(
00883                                 stored_sub_tel_data_headers[ifu_nr-1], 
00884                                 QC_THROUGHPUT, 
00885                                 stored_qc_throughput[ifu_nr-1], 
00886                                 "[] IFU throughput");
00887 
00888                         /* QC ZEROPOINT */
00889                         zeropoint = kmo_calc_zeropoint(magnitude1, magnitude2, 
00890                                 counts1, counts2, cdelt1, filter_id);
00891                         if (kmclipm_is_nan_or_inf(zeropoint)) zeropoint = -1;
00892                         kmclipm_update_property_double(
00893                                 stored_sub_tel_data_headers[ifu_nr-1], 
00894                                 QC_ZEROPOINT, zeropoint, "[mag] IFU zeropoint");
00895                     }
00896                     /* Update number of standard stars */
00897                     nr_std_stars++;
00898                     cpl_vector_delete(spec_qc) ;
00899                 }
00900             } else {
00901                 cpl_error_reset();
00902                 /* IFU is invalid */
00903                 stored_telluric_data[ifu_nr-1] = NULL ;
00904                 stored_telluric_noise[ifu_nr-1] = NULL ;
00905                 stored_starspec_data[ifu_nr-1] = NULL ;
00906                 stored_starspec_noise[ifu_nr-1] = NULL ;
00907                 stored_psf_data[ifu_nr-1] = NULL ;
00908                 stored_mask[ifu_nr-1] = NULL ;
00909                 stored_data_cube[ifu_nr-1] = NULL ;
00910                 stored_noise_cube[ifu_nr-1] = NULL ;
00911                 stored_noisespec[ifu_nr-1] = NULL ;
00912 
00913                 stored_sub_tel_data_headers[ifu_nr-1] =
00914                     cpl_propertylist_duplicate(sub_header_orig);
00915                 stored_sub_tel_noise_headers[ifu_nr-1] =
00916                     cpl_propertylist_duplicate(sub_header_orig);
00917                 stored_sub_psf_headers[ifu_nr-1] =
00918                     cpl_propertylist_duplicate(sub_header_orig);
00919                 stored_sub_cube_data_headers[ifu_nr-1] =
00920                     cpl_propertylist_duplicate(sub_header_orig);
00921                 stored_sub_cube_noise_headers[ifu_nr-1] =
00922                     cpl_propertylist_duplicate(sub_header_orig);
00923             }
00924 
00925             /* EXTNAME for DATA */
00926             extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_DATA);
00927             kmclipm_update_property_string(
00928                     stored_sub_tel_data_headers[ifu_nr-1], EXTNAME, extname,
00929                     "FITS extension name");
00930             kmclipm_update_property_string(
00931                     stored_sub_psf_headers[ifu_nr-1], EXTNAME, extname, 
00932                     "FITS extension name");
00933             kmclipm_update_property_string(
00934                     stored_sub_cube_data_headers[ifu_nr-1], EXTNAME, 
00935                     extname, "FITS extension name");
00936             cpl_free(extname);
00937 
00938             /* EXTNAME for NOISE */
00939             if (stored_sub_tel_noise_headers[ifu_nr-1] == NULL) {
00940                 stored_sub_tel_noise_headers[ifu_nr-1] =
00941                     cpl_propertylist_duplicate(
00942                             stored_sub_tel_data_headers[ifu_nr-1]);
00943             }
00944             extname = kmo_extname_creator(ifu_frame, ifu_nr, EXT_NOISE);
00945             kmclipm_update_property_string(
00946                     stored_sub_tel_noise_headers[ifu_nr-1], EXTNAME, 
00947                     extname, "FITS extension name");
00948             if (stored_sub_cube_noise_headers[ifu_nr-1] == NULL)
00949                 stored_sub_cube_noise_headers[ifu_nr-1] =
00950                     cpl_propertylist_duplicate(
00951                             stored_sub_cube_data_headers[ifu_nr-1]);
00952             kmclipm_update_property_string(
00953                     stored_sub_cube_noise_headers[ifu_nr-1], EXTNAME,
00954                         extname, "FITS extension name");
00955             cpl_free(extname);
00956         } 
00957         cpl_propertylist_delete(sub_header_orig);
00958     } 
00959     cpl_free(bounds);
00960 
00961     /* Write QC parameter: nr of std stars */
00962     kmclipm_update_property_int(main_header_tel, QC_NR_STD_STARS,
00963             nr_std_stars, "[] Nr. of std stars");
00964 
00965     /* Update which IFUs are not used */
00966     kmo_print_unused_ifus(unused_ifus_after, TRUE);
00967     kmo_set_unused_ifus(unused_ifus_after, main_header_tel,"kmos_std_star");
00968     kmo_free_unused_ifus(unused_ifus_after);
00969 
00970     main_header_psf = cpl_propertylist_duplicate(main_header_tel);
00971 
00972     if (compute_qcs) {
00973         /* QC THROUGHPUT MEAN and QC THROUGHPUT SDV */
00974         kmo_calc_mean_throughput(stored_qc_throughput, nifus, &throughput_mean,
00975                 &throughput_sdv);
00976         cpl_free(stored_qc_throughput);
00977         kmclipm_update_property_double(main_header_tel, QC_THROUGHPUT_MEAN,
00978                 throughput_mean, "[] mean throughput for all detectors");
00979         kmclipm_update_property_double(main_header_tel, QC_THROUGHPUT_SDV,
00980                 throughput_sdv, "[] stdev throughput for all detectors");
00981     }
00982     
00983     /* Save output data */
00984     if (!suppress_extension)    fn_suffix = cpl_sprintf("%s", suffix);
00985     else                        fn_suffix = cpl_sprintf("%s", "");
00986     cpl_free(suffix); 
00987 
00988     /* Save primary extension */
00989     kmo_dfs_save_main_header(frameset, filename_telluric, fn_suffix,
00990             obj_frame, main_header_tel, parlist, cpl_func);
00991     kmo_dfs_save_main_header(frameset, filename_starspec, fn_suffix,
00992             obj_frame, main_header_tel, parlist, cpl_func);
00993     kmo_dfs_save_main_header(frameset, filename_mask, fn_suffix,
00994             obj_frame, main_header_psf, parlist, cpl_func);
00995     kmo_dfs_save_main_header(frameset, filename_psf, fn_suffix,
00996             obj_frame, main_header_psf, parlist, cpl_func) ;
00997     if (!no_noise && is_stdstarscipatt) {
00998         kmo_dfs_save_main_header(frameset, filename_noise, fn_suffix,
00999                 obj_frame, main_header_tel, parlist, cpl_func);
01000     }
01001     cpl_propertylist_delete(main_header_tel);
01002     
01003     if (save_cubes) {
01004         kmo_dfs_save_main_header(frameset, filename_cubes, fn_suffix,
01005                 obj_frame, main_header_psf, parlist, cpl_func);
01006     }
01007     cpl_propertylist_delete(main_header_psf);
01008 
01009     /* Save stored frames */
01010     for (i = 1; i <= KMOS_NR_DETECTORS ; i++) {
01011         for (j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
01012             ifu_nr = (i-1)*KMOS_IFUS_PER_DETECTOR + j + 1;
01013 
01014             /* Save telluric-vector */
01015             if (stored_telluric_data[ifu_nr-1] != NULL) {
01016                 ddd = kmclipm_vector_create(cpl_vector_duplicate(
01017                             stored_telluric_data[ifu_nr-1]));
01018                 kmo_dfs_save_vector(ddd, filename_telluric, fn_suffix,
01019                         stored_sub_tel_data_headers[ifu_nr-1], 0./0.);
01020                 kmclipm_vector_delete(ddd) ;
01021             } else {
01022                 kmo_dfs_save_vector(NULL, filename_telluric, fn_suffix,
01023                         stored_sub_tel_data_headers[ifu_nr-1], 0./0.);
01024             }
01025             if (stored_telluric_noise[ifu_nr-1] != NULL) {
01026                 ddd = kmclipm_vector_create(cpl_vector_duplicate(
01027                             stored_telluric_noise[ifu_nr-1]));
01028                 kmo_dfs_save_vector(ddd, filename_telluric, fn_suffix,
01029                         stored_sub_tel_noise_headers[ifu_nr-1], 0./0.);
01030                 kmclipm_vector_delete(ddd) ;
01031             } else {
01032                 kmo_dfs_save_vector(NULL, filename_telluric, fn_suffix,
01033                         stored_sub_tel_noise_headers[ifu_nr-1], 0./0.);
01034             }
01035 
01036             /* Save star_spec-vector */
01037             if (stored_starspec_data[ifu_nr-1] != NULL) {
01038                 ddd = kmclipm_vector_create(cpl_vector_duplicate(
01039                             stored_starspec_data[ifu_nr-1]));
01040                 kmo_dfs_save_vector(ddd, filename_starspec, fn_suffix,
01041                         stored_sub_tel_data_headers[ifu_nr-1], 0./0.);
01042                 kmclipm_vector_delete(ddd); 
01043             } else {
01044                 kmo_dfs_save_vector(NULL, filename_starspec, fn_suffix,
01045                         stored_sub_tel_data_headers[ifu_nr-1], 0./0.);
01046             }
01047             if (stored_starspec_noise[ifu_nr-1] != NULL) {
01048                 ddd = kmclipm_vector_create(cpl_vector_duplicate(
01049                             stored_starspec_noise[ifu_nr-1]));
01050                 kmo_dfs_save_vector(ddd, filename_starspec, fn_suffix,
01051                         stored_sub_tel_noise_headers[ifu_nr-1], 0./0.);
01052                 kmclipm_vector_delete(ddd); 
01053             } else {
01054                 kmo_dfs_save_vector(NULL, filename_starspec, fn_suffix,
01055                         stored_sub_tel_noise_headers[ifu_nr-1], 0./0.);
01056             }
01057 
01058             /* Save psf-image */
01059             kmo_dfs_save_image(stored_psf_data[ifu_nr-1], filename_psf, 
01060                     fn_suffix, stored_sub_psf_headers[ifu_nr-1], 0./0.);
01061 
01062             /* Save mask-image */
01063             kmo_dfs_save_image(stored_mask[ifu_nr-1], filename_mask, 
01064                     fn_suffix, stored_sub_psf_headers[ifu_nr-1], 0./0.);
01065 
01066             /* Save noise_spec-vector */
01067             if (!no_noise && is_stdstarscipatt && stored_noisespec != NULL && 
01068                     stored_noisespec[ifu_nr-1] != NULL && 
01069                     stored_starspec_data[ifu_nr-1] != NULL) {
01070                 /* QC SNR */
01071                 kmo_calc_band_mean(stored_sub_tel_data_headers[ifu_nr-1],
01072                         filter_id, stored_starspec_data[ifu_nr-1], NULL,
01073                         &tmp_data, NULL);
01074                 kmo_calc_band_mean(stored_sub_tel_data_headers[ifu_nr-1],
01075                         filter_id, stored_noisespec[ifu_nr-1], NULL,
01076                         &tmp_noise, NULL);
01077                 kmclipm_update_property_double(
01078                         stored_sub_tel_data_headers[ifu_nr-1], QC_SNR,
01079                         tmp_data/tmp_noise, "[] SNR");
01080             }
01081 
01082             if (!no_noise && is_stdstarscipatt) {
01083                 if ((stored_noisespec != NULL) && 
01084                         stored_noisespec[ifu_nr-1] != NULL) {
01085                     ddd = kmclipm_vector_create(cpl_vector_duplicate(
01086                                 stored_noisespec[ifu_nr-1]));
01087                     kmo_dfs_save_vector(ddd, filename_noise, fn_suffix,
01088                             stored_sub_tel_data_headers[ifu_nr-1], 0./0.);
01089                     kmclipm_vector_delete(ddd); 
01090                 } else {
01091                     kmo_dfs_save_vector(NULL, filename_noise, fn_suffix,
01092                             stored_sub_tel_data_headers[ifu_nr-1], 0./0.);
01093                 }
01094             }
01095 
01096             /* Save reonstructed cubes */
01097             if (save_cubes) {
01098                 kmo_dfs_save_cube(stored_data_cube[ifu_nr-1],
01099                         filename_cubes, fn_suffix,
01100                         stored_sub_cube_data_headers[ifu_nr-1], 0./0.);
01101                 kmo_dfs_save_cube(stored_noise_cube[ifu_nr-1],
01102                         filename_cubes, fn_suffix,
01103                         stored_sub_cube_noise_headers[ifu_nr-1], 0./0.);
01104             }
01105         } 
01106     } 
01107     cpl_free(fn_suffix);
01108 
01109     /* DE-Allocate Warning ---  Frames (e.g obj_frame) point to  */
01110     /*                          obj_..._struct which point to frameset_ѕtd */
01111     kmo_delete_objSkyStruct(obj_sky_struct);
01112     kmo_delete_skySkyStruct(sky_sky_struct);
01113     cpl_frameset_delete(frameset_std);
01114     
01115     for (i = 0; i < nifus ; i++) {
01116         cpl_vector_delete(stored_telluric_data[i]);
01117         cpl_vector_delete(stored_telluric_noise[i]);
01118         cpl_vector_delete(stored_starspec_data[i]); 
01119         cpl_vector_delete(stored_starspec_noise[i]);
01120         cpl_image_delete(stored_psf_data[i]);
01121         cpl_propertylist_delete(stored_sub_tel_data_headers[i]); 
01122         cpl_propertylist_delete(stored_sub_tel_noise_headers[i]);
01123         cpl_vector_delete(stored_noisespec[i]); 
01124         cpl_propertylist_delete(stored_sub_cube_data_headers[i]); 
01125         cpl_propertylist_delete(stored_sub_cube_noise_headers[i]);
01126         cpl_propertylist_delete(stored_sub_psf_headers[i]); 
01127         cpl_image_delete(stored_mask[i]);
01128         cpl_imagelist_delete(stored_data_cube[i]);
01129         cpl_imagelist_delete(stored_noise_cube[i]);
01130     }
01131     cpl_free(stored_telluric_data);
01132     cpl_free(stored_telluric_noise);
01133     cpl_free(stored_starspec_data);
01134     cpl_free(stored_starspec_noise); 
01135     cpl_free(stored_psf_data);
01136     cpl_free(stored_sub_tel_data_headers);
01137     cpl_free(stored_sub_tel_noise_headers);
01138     cpl_free(stored_noisespec);
01139     cpl_free(stored_sub_cube_data_headers);
01140     cpl_free(stored_sub_cube_noise_headers);
01141     cpl_free(stored_sub_psf_headers);
01142     cpl_free(stored_mask);
01143     cpl_free(stored_data_cube);
01144     cpl_free(stored_noise_cube);
01145 
01146     return 0;
01147 }
01148 
01152 /*----------------------------------------------------------------------------*/
01157 /*----------------------------------------------------------------------------*/
01158 static int kmos_std_star_compute_ifu(
01159         cpl_propertylist    *   sub_header_orig,
01160         cpl_frame           *   obj_frame,
01161         cpl_frame           *   sky_frame,
01162         cpl_frame           *   flat_frame,
01163         cpl_frame           *   xcal_frame,
01164         cpl_frame           *   ycal_frame,
01165         cpl_frame           *   lcal_frame,
01166         cpl_frame           *   illum_frame,
01167         cpl_frame           *   atmos_frame,
01168         cpl_frame           *   solar_frame,
01169         int                     ifu_nr,
01170         cpl_propertylist    *   main_header_tel,
01171         gridDefinition          gd,
01172         int                     low_bound,
01173         int                     high_bound,
01174         const char          *   fmethod,
01175         int                     flux,
01176         int                     xcal_interpolation,
01177         const char          *   cmethod,
01178         double                  cpos_rej,
01179         double                  cneg_rej,
01180         int                     citer,
01181         int                     cmax,
01182         int                     cmin,
01183         const char          *   filter_id,
01184         char                    star_type,
01185         int                     no_noise,
01186         int                     is_stdstarscipatt,
01187         skySkyStruct            sky_sky_struct,
01188         double                  star_temp,
01189         cpl_vector          **  spec_qc,
01190         cpl_propertylist    **  out_sub_tel_data_header,
01191         cpl_propertylist    **  out_sub_psf_header,
01192         cpl_propertylist    **  out_sub_cube_data_header,
01193         cpl_imagelist       **  out_data_cube,
01194         cpl_imagelist       **  out_noise_cube,
01195         cpl_image           **  out_psf_data,
01196         cpl_image           **  out_mask,
01197         cpl_vector          **  out_starspec_data,
01198         cpl_vector          **  out_starspec_noise,
01199         cpl_vector          **  out_noisespec,
01200         cpl_vector          **  out_telluric_data,
01201         cpl_vector          **  out_telluric_noise)
01202 {
01203     char                *   keyword ;
01204     cpl_propertylist    *   tmp_head ;
01205     cpl_image           *   illum_corr ;
01206     cpl_propertylist    *   pl_psf ;
01207     double                  std_trace, factor_fwhm, spat_res ;
01208     cpl_vector          *   tmp_vec ;
01209     cpl_vector          *   tmp_spec_data ;
01210     cpl_vector          *   tmp_spec_noise ;
01211     cpl_vector          *   shot_noise ;
01212     cpl_vector          *   solar_spec ;
01213     double              *   ppp ;
01214     double                  gain, mean_data, mean_data2, flux_scale_factor ;
01215     double              **  pvec_array ;
01216     double              *   ptmp_vec ;
01217     double              *   pstored_noisespec ;
01218     cpl_vector          **  vec_array ;
01219     const double        *   ptmp_spec_data ;
01220     double              *   ptmp_spec_noise ;
01221     cpl_imagelist       *   tmp_cube ;
01222     cpl_vector          *   lambda_x ;
01223     cpl_vector          *   atmos_model ;
01224     int                     i, j, k, nr_sky_pairs, npix ;
01225  
01226     /* Check inputs */
01227     
01228     /* Initialise */
01229     std_trace = -1.0 ;
01230 
01231     /* Messages */
01232     if (sky_frame != NO_CORRESPONDING_SKYFRAME) {
01233         cpl_msg_info(cpl_func, "Processing standard star in IFU %d", ifu_nr);
01234         cpl_msg_info(cpl_func, "   (obj: %s, sky: %s)",
01235                 cpl_frame_get_filename(obj_frame),
01236                 cpl_frame_get_filename(sky_frame));
01237     } else {
01238         sky_frame = NULL;
01239         cpl_msg_warning(cpl_func, 
01240                 "Processing standard star in IFU %d", ifu_nr);
01241         cpl_msg_warning(cpl_func, 
01242                 "   (obj: %s, no corresponding sky frame)",
01243                 cpl_frame_get_filename(obj_frame));
01244     }
01245 
01246     keyword = cpl_sprintf("%s%d", PRO_STD, ifu_nr);
01247     cpl_propertylist_update_int(main_header_tel, keyword, 1);
01248     cpl_free(keyword);
01249 
01250     /* Compute WCS and make copies of sub_header */
01251     tmp_head=cpl_propertylist_duplicate(sub_header_orig);
01252     kmo_calc_wcs_gd(main_header_tel, tmp_head, ifu_nr,gd);
01253     *out_sub_tel_data_header = cpl_propertylist_duplicate(tmp_head);
01254     *out_sub_psf_header = cpl_propertylist_duplicate(tmp_head);
01255     *out_sub_cube_data_header = cpl_propertylist_duplicate(tmp_head);
01256     cpl_propertylist_delete(tmp_head);
01257     
01258     /* Adjust telluric-headers: copy key3 to key1 - rm key2 key3*/
01259     kmos_std_star_adjust_double(*out_sub_tel_data_header, CRVAL1,CRVAL2,CRVAL3);
01260     kmos_std_star_adjust_double(*out_sub_tel_data_header, CRPIX1,CRPIX2,CRPIX3);
01261     kmos_std_star_adjust_double(*out_sub_tel_data_header, CDELT1,CDELT2,CDELT3);
01262     kmos_std_star_adjust_string(*out_sub_tel_data_header, CTYPE1,CTYPE2,CTYPE3);
01263     kmos_std_star_adjust_string(*out_sub_tel_data_header, CUNIT1,CUNIT2,CUNIT3);
01264 
01265     /* CDx_x */
01266     cpl_propertylist_erase(*out_sub_tel_data_header, CD1_1);
01267     cpl_propertylist_erase(*out_sub_tel_data_header, CD1_2);
01268     cpl_propertylist_erase(*out_sub_tel_data_header, CD1_3);
01269     cpl_propertylist_erase(*out_sub_tel_data_header, CD2_1);
01270     cpl_propertylist_erase(*out_sub_tel_data_header, CD2_2);
01271     cpl_propertylist_erase(*out_sub_tel_data_header, CD2_3);
01272     cpl_propertylist_erase(*out_sub_tel_data_header, CD3_1);
01273     cpl_propertylist_erase(*out_sub_tel_data_header, CD3_2);
01274     cpl_propertylist_erase(*out_sub_tel_data_header, CD3_3);
01275 
01276     /* Adjust psf-headers: delete CRPIX3 etc. */
01277     cpl_propertylist_erase(*out_sub_psf_header, CRPIX3);
01278     cpl_propertylist_erase(*out_sub_psf_header, CRPIX3);
01279     cpl_propertylist_erase(*out_sub_psf_header, CDELT3);
01280     cpl_propertylist_erase(*out_sub_psf_header, CRVAL3);
01281     cpl_propertylist_erase(*out_sub_psf_header, CTYPE3);
01282     cpl_propertylist_erase(*out_sub_psf_header, CUNIT3);
01283     cpl_propertylist_erase(*out_sub_psf_header, CD1_3);
01284     cpl_propertylist_erase(*out_sub_psf_header, CD2_3);
01285     cpl_propertylist_erase(*out_sub_psf_header, CD3_1);
01286     cpl_propertylist_erase(*out_sub_psf_header, CD3_2);
01287     cpl_propertylist_erase(*out_sub_psf_header, CD3_3);
01288         
01289     /* Reconstruct */
01290     kmo_reconstruct_sci(ifu_nr, low_bound, high_bound, obj_frame, STD,
01291             sky_frame, STD, flat_frame, xcal_frame, ycal_frame, lcal_frame,
01292             NULL, NULL, &gd, out_data_cube, out_noise_cube, flux, FALSE,
01293             xcal_interpolation);
01294 
01295     /* Illumination correction */
01296     /* Illumination noise small versus noise - skipped */
01297     if (illum_frame != NULL) {
01298         illum_corr = kmo_dfs_load_image_frame(illum_frame, 
01299                 ifu_nr, FALSE, FALSE, NULL);
01300         cpl_imagelist_divide_image(*out_data_cube, illum_corr);
01301         cpl_image_delete(illum_corr);
01302     }
01303 
01304     /* QC_STD_TRACE (distance of the PSF to the centre) */
01305     kmo_calculate_std_trace(*out_data_cube, fmethod, &std_trace);
01306     kmclipm_update_property_double(*out_sub_psf_header, QC_STD_TRACE, std_trace,
01307             "[pix] distance PSF - IFU center");
01308 
01309     /* Collapse cube and get PSF image */
01310     kmclipm_make_image(*out_data_cube, NULL, out_psf_data, NULL, NULL,
01311             cmethod, cpos_rej, cneg_rej, citer, cmax, cmin);
01312 
01313     /* Fit a 2D profile to get a mask and fwhm in x and y */
01314     tmp_vec = kmo_fit_profile_2D(*out_psf_data, NULL, fmethod,out_mask,&pl_psf);
01315 
01316     /* Normalise mask to 1 and clip values below 0.5 */
01317     cpl_image_divide_scalar(*out_mask, cpl_image_get_max(*out_mask));
01318     for (i = 1; i <= cpl_image_get_size_x(*out_mask); i++) {
01319         for (j = 1; j <= cpl_image_get_size_y(*out_mask); j++) {
01320             if (cpl_image_get(*out_mask, i, j, &k) < 0.5) 
01321                 cpl_image_set(*out_mask, i, j, 0.);
01322             else   
01323                 cpl_image_set(*out_mask, i, j, 1.);
01324         }
01325     }
01326 
01327     /* Update subheader with fit parameters */
01328     cpl_propertylist_append(*out_sub_tel_data_header, pl_psf);
01329     cpl_propertylist_delete(pl_psf);
01330 
01331     /* QC_SPAT_RES (RMS of fwhm_x and fwhm_y) */
01332     factor_fwhm = 2*sqrt(2*log(2));
01333     spat_res = pow(cpl_vector_get(tmp_vec, 4) * factor_fwhm, 2);
01334     spat_res += pow(cpl_vector_get(tmp_vec, 5)* factor_fwhm, 2);
01335     spat_res /= 2;
01336     kmclipm_update_property_double(*out_sub_psf_header, QC_SPAT_RES,
01337             sqrt(spat_res)*KMOS_PIX_RESOLUTION,
01338             "[arcsec] mean fwhm resolution of PSF");
01339     cpl_vector_delete(tmp_vec);
01340     
01341     /* Extract spectrum with mask  */
01342     /* Convert Mean to Sum (* mask area) */
01343     tmp_spec_data = tmp_spec_noise = NULL ;
01344     kmo_priv_extract_spec(*out_data_cube, *out_noise_cube, *out_mask,
01345             &tmp_spec_data, &tmp_spec_noise);
01346     cpl_vector_multiply_scalar(tmp_spec_data, cpl_image_get_flux(*out_mask));
01347     if (tmp_spec_noise != NULL) {
01348         cpl_vector_multiply_scalar(tmp_spec_noise,
01349                 cpl_image_get_flux(*out_mask));
01350     }
01351    
01352     /* Extract spectrum of whole area for QCs */
01353     /* Convert mean to sum (* 196, IFU area) */
01354     tmp_vec = *spec_qc = NULL ;
01355     kmo_priv_extract_spec(*out_data_cube, *out_noise_cube, NULL, spec_qc,
01356             &tmp_vec);
01357     npix = cpl_image_get_size_x(cpl_imagelist_get(*out_data_cube, 0)) * 
01358         cpl_image_get_size_y(cpl_imagelist_get(*out_data_cube, 0)) ;
01359     cpl_vector_multiply_scalar(*spec_qc, npix);
01360     if (tmp_vec != NULL) cpl_vector_multiply_scalar(tmp_vec, npix);
01361 
01362     /* Shot noise */
01363     gain = cpl_propertylist_get_double(*out_sub_tel_data_header, GAIN);
01364 
01365     /* Shot_noise = sqrt(tmp_spec_data*gain)/gain */
01366     /* set negative values and NaN's to zero before sqrt */
01367     shot_noise = cpl_vector_duplicate(tmp_spec_data);
01368     cpl_vector_multiply_scalar(shot_noise, gain);
01369     ppp = cpl_vector_get_data(shot_noise);
01370     for (i = 0; i < cpl_vector_get_size(shot_noise); i++) {
01371         if ((ppp[i] < 0.0) || kmclipm_is_nan_or_inf(ppp[i])) 
01372             ppp[i] = 0.0;
01373     }
01374     cpl_vector_sqrt(shot_noise);
01375     cpl_vector_divide_scalar(shot_noise, gain);
01376 
01377     /* Scale extracted spectrum to match the one  */
01378     /* calculated over the whole area (band specific) */
01379     kmo_calc_band_mean(*out_sub_tel_data_header, filter_id, tmp_spec_data, 
01380             tmp_spec_noise, &mean_data, NULL);
01381     kmo_calc_band_mean(*out_sub_tel_data_header, filter_id, *spec_qc, tmp_vec, 
01382             &mean_data2, NULL);
01383     cpl_vector_delete(tmp_vec) ;
01384 
01385     flux_scale_factor = mean_data2/mean_data;
01386 
01387     cpl_vector_multiply_scalar(shot_noise, flux_scale_factor);
01388     cpl_vector_multiply_scalar(tmp_spec_data,flux_scale_factor);
01389     if ((tmp_spec_noise != NULL) && (fabs(mean_data) > 1e-8))
01390         cpl_vector_multiply_scalar(tmp_spec_noise, flux_scale_factor);
01391 
01392     /* Store to save to disk later on */
01393     *out_starspec_data = cpl_vector_duplicate(tmp_spec_data);
01394     if (tmp_spec_noise != NULL) 
01395         *out_starspec_noise = cpl_vector_duplicate(tmp_spec_noise);
01396     else
01397         *out_starspec_noise = NULL ;
01398 
01399     /* Noise spectra */
01400     if (!no_noise && is_stdstarscipatt) {
01401         nr_sky_pairs = sky_sky_struct.nrSkyPairs;
01402         if (nr_sky_pairs > 2) {
01403             cpl_msg_info(__func__, "Get noise spec on sky for IFU %d", ifu_nr);
01404             vec_array = cpl_calloc(nr_sky_pairs,sizeof(cpl_vector*));
01405             pvec_array = cpl_calloc(nr_sky_pairs, sizeof(double*));
01406             /* Reconstruct all sky-Pairs, extract spectra  */
01407             for (i = 0; i < nr_sky_pairs; i++) {
01408                 // reconstruct (sky1-sky2)/flatfield
01409                 kmo_reconstruct_sci(ifu_nr, low_bound, high_bound,
01410                         sky_sky_struct.skyPairs[i].skyFrame1, STD, 
01411                         sky_sky_struct.skyPairs[i].skyFrame2, STD, flat_frame,
01412                         xcal_frame, ycal_frame, lcal_frame, NULL, NULL, &gd, 
01413                         &tmp_cube, NULL, FALSE, FALSE, xcal_interpolation);
01414 
01415                 /* Extract spectrum using masked   */
01416                 /* convert mean to sum (* mask aperture) */
01417                 kmo_priv_extract_spec(tmp_cube, NULL, *out_mask, 
01418                         &(vec_array[i]), NULL);
01419                 cpl_vector_multiply_scalar(vec_array[i], 
01420                         cpl_image_get_flux(*out_mask));
01421 
01422                 /* Scale extracted spectrum to match the one  */
01423                 /* calculated over the whole area (band spec) */
01424                 cpl_vector_multiply_scalar(vec_array[i], flux_scale_factor);
01425                 pvec_array[i] = cpl_vector_get_data(vec_array[i]);
01426                 cpl_imagelist_delete(tmp_cube);
01427             }
01428 
01429             /* stddev on each wavelength of all extrac spec */
01430             *out_noisespec = cpl_vector_new(gd.l.dim);
01431             pstored_noisespec = cpl_vector_get_data(*out_noisespec);
01432             tmp_vec = cpl_vector_new(nr_sky_pairs);
01433             ptmp_vec = cpl_vector_get_data(tmp_vec);
01434             for (i = 0; i < gd.l.dim; i++) {
01435                 for (j = 0; j < nr_sky_pairs; j++) 
01436                     ptmp_vec[j] = pvec_array[j][i];
01437                 pstored_noisespec[i] = cpl_vector_get_stdev(tmp_vec);
01438             }
01439             for (i = 0; i < nr_sky_pairs; i++) cpl_vector_delete(vec_array[i]);
01440             cpl_free(vec_array);
01441             cpl_free(pvec_array);
01442             cpl_vector_delete(tmp_vec);
01443             
01444             /* total noise = sqrt (shot_noise^2+sky_noise^2) */
01445             // and set negative values and NaN's to zero
01446             cpl_vector_power(*out_noisespec, 2.);
01447             cpl_vector_power(shot_noise, 2.);
01448             cpl_vector_add(*out_noisespec, shot_noise);
01449             ppp = cpl_vector_get_data(*out_noisespec);
01450             for (i = 0; i < cpl_vector_get_size(*out_noisespec); i++) {
01451                 if ((ppp[i] < 0.0) || kmclipm_is_nan_or_inf(ppp[i])) ppp[i]=0.0;
01452             }
01453             cpl_vector_sqrt(*out_noisespec);
01454             cpl_vector_delete(shot_noise); 
01455         } else {
01456             cpl_msg_warning(__func__, "Omit noise-spectra (<2 sky pairs)");
01457             *out_noisespec = shot_noise;
01458         }
01459     } else {
01460         *out_noisespec = shot_noise;
01461     } 
01462 
01463     /* Spectrum correction */
01464     /* Abscissa of output spectrum */
01465     lambda_x = kmo_create_lambda_vec(gd.l.dim, 1, gd.l.start, gd.l.delta);
01466 
01467     if (star_type=='O' || star_type=='B' || star_type=='A' || star_type=='F') {
01468         /* OBAF star */
01469 
01470         /* Remove lines if ATMOS_MODEL is provided */
01471         if (atmos_frame != NULL) {
01472             /* Interpolate ATMOS_MODEL to same scale as data */
01473             atmos_model = kmo_interpolate_vector_wcs(atmos_frame, lambda_x);
01474 
01475             /* Remove band-specific lines */
01476             if (!strcmp(filter_id, "H")) 
01477                 for (i = 0; i < nr_lines_h; i++) 
01478                     kmo_remove_line(tmp_spec_data, lambda_x, atmos_model, 
01479                             lines_center_h[i], lines_width_h[i]);
01480             else if (!strcmp(filter_id, "HK"))
01481                 for (i = 0; i < nr_lines_hk; i++) 
01482                     kmo_remove_line(tmp_spec_data, lambda_x, atmos_model, 
01483                             lines_center_hk[i], lines_width_hk[i]);
01484             else if (!strcmp(filter_id, "K")) 
01485                 for (i = 0; i < nr_lines_k; i++) 
01486                     kmo_remove_line(tmp_spec_data, lambda_x, atmos_model, 
01487                             lines_center_k[i], lines_width_k[i]);
01488             else if (!strcmp(filter_id, "IZ")) 
01489                 for (i = 0; i < nr_lines_iz; i++) 
01490                     kmo_remove_line(tmp_spec_data, lambda_x, atmos_model, 
01491                             lines_center_iz[i], lines_width_iz[i]);
01492             else if (strcmp(filter_id, "YJ") == 0)
01493                 for (i = 0; i < nr_lines_yj; i++) 
01494                     kmo_remove_line(tmp_spec_data, lambda_x, atmos_model, 
01495                             lines_center_yj[i], lines_width_yj[i]);
01496             
01497             if (0) kmos_std_star_plot() ;
01498             cpl_vector_delete(atmos_model);
01499         } else {
01500             cpl_msg_warning(__func__, "Missing ATMOS_MODEL");
01501         }
01502     } else if (star_type == 'G') {
01503         /* G star */
01504         if (solar_frame != NULL) {
01505             /* Interpolate SOLAR_SPEC to same scale and divide it */
01506             solar_spec = kmo_interpolate_vector_wcs(solar_frame, 
01507                     lambda_x);
01508             /* Set to zero if solar_spec isn't overlapping  */
01509             /* wavelength range of star apectrum completely */
01510             cpl_vector_divide(tmp_spec_data, solar_spec);
01511             cpl_vector_delete(solar_spec); 
01512         } else {
01513             cpl_msg_warning(__func__, "Missing SOLAR_SPEC");
01514         }
01515     }
01516 
01517     if (star_temp > 0.0) {
01518         /* Divide blackbody from tmp_spec_data */
01519         kmo_divide_blackbody(tmp_spec_data, lambda_x, star_temp);
01520     }
01521     cpl_vector_delete(lambda_x);
01522 
01523     /* Normalise telluric and its noise */
01524     /* mean is taken in lambda defined range */
01525     kmo_calc_band_mean(*out_sub_tel_data_header, filter_id, tmp_spec_data, 
01526             tmp_spec_noise, &mean_data, NULL);
01527     cpl_vector_divide_scalar(tmp_spec_data, mean_data);
01528 
01529     if (tmp_spec_noise != NULL) {
01530         /* Scale noise with the same factor as data */
01531         cpl_vector_divide_scalar(tmp_spec_noise, mean_data);
01532 
01533         /* Set noise spectrum to zero when solar_spec is short*/
01534         ptmp_spec_data = cpl_vector_get_data_const(tmp_spec_data);
01535         ptmp_spec_noise = cpl_vector_get_data(tmp_spec_noise);
01536         for (i = 0; i < cpl_vector_get_size(tmp_spec_data);i++)
01537             if (ptmp_spec_data[i]==0.0) ptmp_spec_noise[i]=0.0;
01538     }
01539 
01540     /* Store telluric & error spectrum */
01541     *out_telluric_data = tmp_spec_data;
01542     *out_telluric_noise = tmp_spec_noise;
01543     return 0 ;
01544 }
01545 
01546 /*----------------------------------------------------------------------------*/
01556 /*----------------------------------------------------------------------------*/
01557 static int kmos_std_star_check_inputs(
01558         cpl_frameset            *   frameset,
01559         const char              *   magnitude_txt,
01560         int                     *   is_stdstarscipatt,
01561         int                     *   compute_qcs,
01562         double                  *   magnitude1,
01563         double                  *   magnitude2)
01564 {
01565     int                     nb_std, nb_illum, nb_xcal, nb_ycal, nb_lcal,
01566                             nb_flat, nb_wave ;
01567     cpl_frame           *   tmp_frame ;
01568     cpl_frameset        *   frameset_std ;
01569     cpl_propertylist    *   tmp_head ;
01570     const char          *   my_mag_txt ;
01571     int                     nr_split_mag ;
01572     char                **  split_mag ;
01573     char                *   grat_id ;
01574     int                     same_gratings ;
01575     const char          *   tmp_str ;
01576 
01577     /* Check Entries */
01578     if (frameset == NULL || is_stdstarscipatt == NULL || compute_qcs == NULL ||
01579             magnitude1 == NULL || magnitude2 == NULL) return -1;
01580 
01581     /* Count frames */
01582     nb_std = cpl_frameset_count_tags(frameset, STD) ;
01583     nb_illum = cpl_frameset_count_tags(frameset, ILLUM_CORR) ;
01584     nb_xcal = cpl_frameset_count_tags(frameset, XCAL) ;
01585     nb_ycal = cpl_frameset_count_tags(frameset, YCAL) ;
01586     nb_lcal = cpl_frameset_count_tags(frameset, LCAL) ;
01587     nb_flat = cpl_frameset_count_tags(frameset, MASTER_FLAT) ;
01588     nb_wave = cpl_frameset_count_tags(frameset, WAVE_BAND) ;
01589 
01590     /* Check numbers */
01591     if (nb_std < 1) {
01592         cpl_msg_error(__func__, "At least one STD frame is required") ;
01593         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01594         return 0 ;
01595     }
01596     if (nb_std == 1) 
01597         cpl_msg_warning(__func__, "2 STD frames needed for sky subtraction") ;
01598 
01599     if (nb_illum < 0 || nb_illum > 1) {
01600         cpl_msg_error(__func__, "0 or 1 ILLUM frame expected") ;
01601         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01602         return 0 ;
01603     }
01604     if (nb_xcal != 1 || nb_ycal != 1 || nb_lcal != 1) {
01605         cpl_msg_error(__func__, "1 X/Y/LCAL required") ;
01606         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01607         return 0 ;
01608     }
01609     if (nb_flat != 1) {
01610         cpl_msg_error(__func__, "1 MASTER_FLAT required") ;
01611         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01612         return 0 ;
01613     }
01614     if (nb_wave != 1) {
01615         cpl_msg_error(__func__, "1 WAVE_BAND required") ;
01616         cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01617         return 0 ;
01618     }
01619     
01620     /* Extract STD frames with same gratings as the first STD frame */
01621     frameset_std=kmos_std_star_extract_same_grat_stds(frameset,&same_gratings) ;
01622     
01623     /* Get infos from the first STD frame */
01624     tmp_frame = kmo_dfs_get_frame(frameset_std, STD);
01625     tmp_head=kmclipm_propertylist_load(cpl_frame_get_filename(tmp_frame),0);
01626     grat_id = cpl_sprintf("%s", cpl_propertylist_get_string(tmp_head,
01627                 "ESO INS GRAT1 ID"));
01628     if (!strcmp(cpl_propertylist_get_string(tmp_head, TPL_ID),
01629                 "KMOS_spec_cal_stdstarscipatt"))    *is_stdstarscipatt = TRUE ;
01630     else                                            *is_stdstarscipatt = FALSE ;
01631     cpl_propertylist_delete(tmp_head);
01632     cpl_frameset_delete(frameset_std) ;
01633 
01634     /* Check if QC are computed */
01635     if (same_gratings) {
01636         *compute_qcs = TRUE ;
01637         // now check source of magnitude (user or keyword)
01638         tmp_frame = kmo_dfs_get_frame(frameset, STD);
01639         tmp_head=kmclipm_propertylist_load(cpl_frame_get_filename(tmp_frame),0);
01640 
01641         if (!strcmp(magnitude_txt, "")) {
01642             /* No user defined magnitude */
01643             if ((cpl_propertylist_has(tmp_head, STDSTAR_MAG)) &&
01644                 (cpl_propertylist_get_type(tmp_head, STDSTAR_MAG) == 
01645                  CPL_TYPE_STRING)) {
01646                 my_mag_txt = cpl_propertylist_get_string(tmp_head, STDSTAR_MAG);
01647                 split_mag = kmo_strsplit(my_mag_txt, ",", &nr_split_mag);
01648 
01649                 /* Check if band and number of magnitudes matches */
01650                 if (nr_split_mag == 2 && !strcmp(grat_id, "HK")) {
01651                     *magnitude1 = atof(split_mag[0]);
01652                     *magnitude2 = atof(split_mag[1]);
01653                     cpl_msg_info("", "Magnitude in H: %g", *magnitude1);
01654                     cpl_msg_info("", "Magnitude in K: %g", *magnitude2);
01655                 } else if (nr_split_mag >= 1 && (!strcmp(grat_id, "K") ||
01656                             !strcmp(grat_id, "H") || !strcmp(grat_id, "IZ") ||
01657                             !strcmp(grat_id, "YJ"))) {
01658                     *magnitude1 = atof(split_mag[0]);
01659                     cpl_msg_info("", "Magnitude in %s: %g",grat_id,*magnitude1);
01660                 } else {
01661                     // keyword STDSTAR_MAG doesn't match filter
01662                     *compute_qcs = FALSE;
01663                     cpl_msg_warning(cpl_func, "Wrong Mag, QCs not computed") ;
01664                 }
01665                 kmo_strfreev(split_mag);
01666             } else {
01667                 /* STDSTAR_MAG unavailable or wrong type */
01668                 *compute_qcs = FALSE;
01669                 cpl_msg_warning(cpl_func, "%s is not set, QCs not computed", 
01670                         STDSTAR_MAG);
01671             }
01672         } else {
01673             // magnitude is user specified
01674             cpl_msg_info(cpl_func, "Magnitude entered by user, ignore header");
01675 
01676             split_mag = kmo_strsplit(magnitude_txt, ",", &nr_split_mag);
01677             switch (nr_split_mag) {
01678                 case 1:
01679                     *magnitude1 = atof(split_mag[0]);
01680                     cpl_msg_info(cpl_func, "Magnitude in %s: %g", grat_id, 
01681                             *magnitude1);
01682                     break;
01683                 case 2:
01684                     *magnitude1 = atof(split_mag[0]);
01685                     *magnitude2 = atof(split_mag[1]);
01686                     cpl_msg_info("", "Magnitude in H: %g", *magnitude1);
01687                     cpl_msg_info("", "Magnitude in K: %g", *magnitude2);
01688                     break;
01689                 default:
01690                     kmo_strfreev(split_mag);
01691                     cpl_propertylist_delete(tmp_head);
01692                     cpl_msg_error(__func__, "Wrong Magnitude Specified") ;
01693                     cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01694                     return 0 ;
01695             }
01696             kmo_strfreev(split_mag);
01697         }
01698         cpl_propertylist_delete(tmp_head);
01699     } else {
01700         *compute_qcs = FALSE ;
01701     }
01702 
01703     /* Check SOLAR_SPEC grating */
01704     tmp_frame = kmo_dfs_get_frame(frameset, SOLAR_SPEC);
01705     if (tmp_frame != NULL) {
01706         tmp_head=kmclipm_propertylist_load(cpl_frame_get_filename(tmp_frame),0);
01707         tmp_str = cpl_propertylist_get_string(tmp_head, FILT_ID);
01708         if (strcmp(tmp_str, grat_id)) {
01709             cpl_propertylist_delete(tmp_head) ;
01710             cpl_msg_error(__func__, "Wrong SOLAR_SPEC grating") ;
01711             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01712             return 0 ;
01713         }
01714         cpl_propertylist_delete(tmp_head) ;
01715     }
01716 
01717     /* Check ATMOS_MODEL grating */
01718     tmp_frame = kmo_dfs_get_frame(frameset, ATMOS_MODEL);
01719     if (tmp_frame != NULL) {
01720         tmp_head=kmclipm_propertylist_load(cpl_frame_get_filename(tmp_frame),0);
01721         tmp_str = cpl_propertylist_get_string(tmp_head, FILT_ID);
01722         if (strcmp(tmp_str, grat_id)) {
01723             cpl_propertylist_delete(tmp_head) ;
01724             cpl_msg_error(__func__, "Wrong ATMOS_MODEL grating") ;
01725             cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT) ;
01726             return 0 ;
01727         }
01728         cpl_propertylist_delete(tmp_head) ;
01729     }
01730     cpl_free(grat_id) ;
01731 
01732     /* Check if filter_id and grating_id match for all detectors */
01733     kmo_check_frameset_setup(frameset, XCAL, FALSE, FALSE, TRUE);
01734     kmo_check_frame_setup(frameset, XCAL, YCAL, TRUE, FALSE, TRUE);
01735     kmo_check_frame_setup(frameset, XCAL, LCAL, TRUE, FALSE, TRUE);
01736     kmo_check_frame_setup(frameset, XCAL, MASTER_FLAT, TRUE, FALSE, TRUE);
01737     kmo_check_frame_setup(frameset, XCAL, STD, FALSE, FALSE, TRUE);
01738     if (nb_illum == 1) 
01739         kmo_check_frame_setup(frameset, XCAL, ILLUM_CORR, TRUE, FALSE, FALSE);
01740     kmo_check_frame_setup_md5_xycal(frameset);
01741     kmo_check_frame_setup_md5(frameset);
01742     return 1 ;
01743 }
01744 
01745 /*----------------------------------------------------------------------------*/
01751 /*----------------------------------------------------------------------------*/
01752 static int kmos_std_star_plot(void)
01753 {
01754 
01755     /*
01756     cpl_vector *tmp_spec_data_atmo = NULL;
01757     cpl_vector *tmp_spec_data_new = NULL;
01758                         tmp_spec_data_orig=cpl_vector_duplicate(tmp_spec_data);
01759     KMO_TRY_EXIT_IF_NULL(
01760         tmp_spec_data_atmo = cpl_vector_duplicate(tmp_spec_data_orig));
01761     KMO_TRY_EXIT_IF_NULL(
01762         tmp_spec_data_new = cpl_vector_duplicate(tmp_spec_data));
01763     KMO_TRY_EXIT_IF_ERROR(
01764         cpl_vector_divide(tmp_spec_data_atmo, atmos_model));
01765 
01766     char *sss = cpl_sprintf("atmo_div_%s.fits", filter_id);
01767     if (i == 1) {
01768         cpl_vector_save(tmp_spec_data_atmo, sss, CPL_BPP_IEEE_DOUBLE, stored_sub_tel_data_headers[ifu_nr-1], CPL_IO_CREATE);
01769     } else {
01770         cpl_vector_save(tmp_spec_data_atmo, sss, CPL_BPP_IEEE_DOUBLE, stored_sub_tel_data_headers[ifu_nr-1], CPL_IO_EXTEND);
01771     }
01772 
01773     cpl_vector *med_vec = cpl_vector_duplicate(tmp_spec_data_orig);
01774     double  median = cpl_vector_get_median(med_vec);
01775     cpl_vector_delete(med_vec);
01776     int ii = 0;
01777     for (ii = 0; ii < cpl_vector_get_size(tmp_spec_data_orig); ii++) {
01778         if (cpl_vector_get(tmp_spec_data_orig, ii) < median/8)
01779             cpl_vector_set(tmp_spec_data_orig, ii, 0);
01780         if (cpl_vector_get(tmp_spec_data_atmo, ii) < median/8)
01781             cpl_vector_set(tmp_spec_data_atmo, ii, 0);
01782         if (cpl_vector_get(tmp_spec_data_new, ii) < median/8)
01783             cpl_vector_set(tmp_spec_data_new, ii, 0);
01784 
01785         if (cpl_vector_get(tmp_spec_data_orig, ii) > 3*median)
01786             cpl_vector_set(tmp_spec_data_orig, ii, 3*median);
01787         if (cpl_vector_get(tmp_spec_data_atmo, ii) > 3*median)
01788             cpl_vector_set(tmp_spec_data_atmo, ii, 3*median);
01789         if (cpl_vector_get(tmp_spec_data_new, ii) > 3*median)
01790             cpl_vector_set(tmp_spec_data_new, ii, 3*median);
01791     }
01792 
01793     double *pspec_dup = cpl_vector_get_data(tmp_spec_data_atmo);
01794     for (ii = 0; ii < cpl_vector_get_size(tmp_spec_data_atmo); ii++) {
01795         if (kmclipm_is_nan_or_inf(pspec_dup[ii])) {
01796             pspec_dup[ii] = 0.;
01797         }
01798     }
01799 
01800     cpl_bivector *plots[3];
01801     plots[0] = cpl_bivector_wrap_vectors((cpl_vector*)lambda_x, tmp_spec_data_orig);
01802     plots[1] = cpl_bivector_wrap_vectors((cpl_vector*)lambda_x, tmp_spec_data_atmo);
01803     plots[2] = cpl_bivector_wrap_vectors((cpl_vector*)lambda_x, tmp_spec_data_new);
01804     char *options[3] = {"w l t 'original'",
01805                         "w l t 'atmo divided'",
01806                         "w l t 'lines removed'"};
01807     sss = cpl_sprintf("set title '%s-band line removal (DET #%d)';", filter_id, i);
01808     cpl_plot_bivectors(sss,
01809                        (const char**)options, "", (const cpl_bivector**)plots, 3);
01810     cpl_bivector_unwrap_vectors(plots[0]);
01811     cpl_bivector_unwrap_vectors(plots[1]);
01812     cpl_bivector_unwrap_vectors(plots[2]);
01813     cpl_free(sss); sss = NULL;
01814     cpl_vector_delete(tmp_spec_data_orig); tmp_spec_data_orig = NULL;
01815     cpl_vector_delete(tmp_spec_data_atmo); tmp_spec_data_atmo = NULL;
01816     cpl_vector_delete(tmp_spec_data_new); tmp_spec_data_new = NULL;
01817 
01818 */
01819     return 0 ;
01820 }
01821 
01822 /*----------------------------------------------------------------------------*/
01828 /*----------------------------------------------------------------------------*/
01829 static int kmos_std_star_adjust_double(
01830         cpl_propertylist    *   header,
01831         const char          *   key1,
01832         const char          *   key2,
01833         const char          *   key3)
01834 {
01835     if (header==NULL || key1==NULL || key2==NULL || key3==NULL) return -1 ;
01836     cpl_propertylist_update_double(header, key1, 
01837             cpl_propertylist_get_double(header, key3));
01838     cpl_propertylist_erase(header, key2) ;
01839     cpl_propertylist_erase(header, key3) ;
01840     return 0 ;
01841 }
01842 
01843 /*----------------------------------------------------------------------------*/
01849 /*----------------------------------------------------------------------------*/
01850 static int kmos_std_star_adjust_string(
01851         cpl_propertylist    *   header,
01852         const char          *   key1,
01853         const char          *   key2,
01854         const char          *   key3)
01855 {
01856     if (header==NULL || key1==NULL || key2==NULL || key3==NULL) return -1 ;
01857     cpl_propertylist_update_string(header, key1, 
01858             cpl_propertylist_get_string(header, key3));
01859     cpl_propertylist_erase(header, key2) ;
01860     cpl_propertylist_erase(header, key3) ;
01861     return 0 ;
01862 }
01863 
01864 /*----------------------------------------------------------------------------*/
01872 /*----------------------------------------------------------------------------*/
01873 static cpl_frameset * kmos_std_star_extract_same_grat_stds(
01874         cpl_frameset        *   in,
01875         int                 *   same_gratings)
01876 {
01877     cpl_frameset        *   frameset_std ;
01878     cpl_frame           *   tmp_frame ;
01879     cpl_propertylist    *   tmp_header ;
01880     char                *   grat_id ;
01881 
01882     /* Check entries */
01883     if (in == NULL ||  same_gratings== NULL) return NULL ;
01884 
01885     /* Create new frameset */
01886     frameset_std = cpl_frameset_new();
01887 
01888     tmp_frame = kmo_dfs_get_frame(in, STD);
01889     tmp_header = kmclipm_propertylist_load(cpl_frame_get_filename(tmp_frame),0);
01890     grat_id = cpl_sprintf("%s", cpl_propertylist_get_string(tmp_header, 
01891                 "ESO INS GRAT1 ID"));
01892     cpl_propertylist_delete(tmp_header); 
01893     cpl_frameset_insert(frameset_std, cpl_frame_duplicate(tmp_frame));
01894 
01895     tmp_frame = kmo_dfs_get_frame(in, NULL);
01896     *same_gratings = TRUE ;
01897     while (tmp_frame != NULL ) {
01898         tmp_header=kmclipm_propertylist_load(cpl_frame_get_filename(tmp_frame),
01899                 0);
01900         if (!strcmp(grat_id, cpl_propertylist_get_string(tmp_header, 
01901                         "ESO INS GRAT1 ID"))) {
01902             cpl_frameset_insert(frameset_std, cpl_frame_duplicate(tmp_frame));
01903         } else {
01904             *same_gratings = FALSE;
01905         }
01906         cpl_propertylist_delete(tmp_header);
01907 
01908         tmp_frame = kmo_dfs_get_frame(in, NULL);
01909     }
01910     cpl_free(grat_id) ;
01911     return frameset_std ;
01912 }