FORS Pipeline Reference Manual 4.9.20
fors_normalise_flat.c
00001 /* $Id: fors_normalise_flat.c,v 1.6 2013/02/28 15:14:38 cgarcia Exp $
00002  *
00003  * This file is part of the FORS Data Reduction Pipeline
00004  * Copyright (C) 2002-2010 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: cgarcia $
00023  * $Date: 2013/02/28 15:14:38 $
00024  * $Revision: 1.6 $
00025  * $Name: fors-4_9_20 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <math.h>
00033 #include <cpl.h>
00034 #include <moses.h>
00035 #include <fors_dfs.h>
00036 
00037 static int fors_normalise_flat_create(cpl_plugin *);
00038 static int fors_normalise_flat_exec(cpl_plugin *);
00039 static int fors_normalise_flat_destroy(cpl_plugin *);
00040 static int fors_normalise_flat(cpl_parameterlist *, cpl_frameset *);
00041 
00042 static char fors_normalise_flat_description[] =
00043 "This recipe is used to normalise a master flat field frame dividing it\n"
00044 "by its large scale illumination trend. This recipe can be applied both\n"
00045 "to generic multi-slit (MOS/MXU) and to long slit exposures (either LSS, or\n"
00046 "LSS-like MOS/MXU), even if different normalisation methods are applied in\n"
00047 "such different cases. The input master flat field image is the product\n"
00048 "of the recipe fors_flat. The input spectral curvature table, product of\n"
00049 "the recipe fors_detect_spectra, is only required in the case of multi-slit\n"
00050 "data.\n"
00051 "\n"
00052 "In the case of multi-slit data, the flat field spectra are spatially\n"
00053 "rectified, heavily smoothed, and then mapped back on the CCD. Then the\n"
00054 "master flat image is divided by its smoothed counterpart. The smoothing\n"
00055 "may be obtained either by applying a running median filter of specified\n"
00056 "sizes, or by polynomial fitting along the dispersion direction performed\n"
00057 "independently for each row of the spatially remapped spectra.\n"
00058 "\n"
00059 "In the case of long-slit data, the smoothing can still be obtained either\n"
00060 "by applying a running median filter or by polynomial fitting, but the\n"
00061 "polynomial fitting will be performed along the spatial direction, for\n"
00062 "each column of the spectrum.\n"
00063 "\n"
00064 "In the table below the MXU acronym can be alternatively read as MOS or\n"
00065 "LSS.\n\n"
00066 "Input files:\n\n"
00067 "  DO category:               Type:       Explanation:         Required:\n"
00068 "  MASTER_SCREEN_FLAT_MXU     Calib       Master flat frame       Y\n"
00069 "  CURV_COEFF_MXU             Calib       Spectral curvature      .\n"
00070 "  GRISM_TABLE                Calib       Grism table             .\n\n"
00071 "Output files:\n\n"
00072 "  DO category:               Data type:  Explanation:\n"
00073 "  MASTER_NORM_FLAT_MXU       FITS image  Normalised flat field\n\n";
00074 
00075 #define fors_normalise_flat_exit(message)     \
00076 {                                             \
00077 if (message) cpl_msg_error(recipe, message);  \
00078 cpl_image_delete(master_flat);                \
00079 cpl_image_delete(spatial);                    \
00080 cpl_image_delete(coordinate);                 \
00081 cpl_image_delete(smo_flat);                   \
00082 cpl_table_delete(grism_table);                \
00083 cpl_table_delete(maskslits);                  \
00084 cpl_table_delete(slits);                      \
00085 cpl_table_delete(polytraces);                 \
00086 cpl_propertylist_delete(header);              \
00087 cpl_msg_indent_less();                        \
00088 return -1;                                    \
00089 }
00090 
00091 #define fors_normalise_flat_exit_memcheck(message)  \
00092 {                                               \
00093 if (message) cpl_msg_info(recipe, message);     \
00094 printf("free master_flat (%p)\n", master_flat); \
00095 cpl_image_delete(master_flat);                  \
00096 printf("free spatial (%p)\n", spatial);         \
00097 cpl_image_delete(spatial);                      \
00098 printf("free coordinate (%p)\n", coordinate);   \
00099 cpl_image_delete(coordinate);                   \
00100 printf("free smo_flat (%p)\n", smo_flat);       \
00101 cpl_image_delete(smo_flat);                     \
00102 printf("free grism_table (%p)\n", grism_table); \
00103 cpl_table_delete(grism_table);                  \
00104 printf("free maskslits (%p)\n", maskslits);     \
00105 cpl_table_delete(maskslits);                    \
00106 printf("free slits (%p)\n", slits);             \
00107 cpl_table_delete(slits);                        \
00108 printf("free polytraces (%p)\n", polytraces);   \
00109 cpl_table_delete(polytraces);                   \
00110 printf("free header (%p)\n", header);           \
00111 cpl_propertylist_delete(header);                \
00112 cpl_msg_indent_less();                          \
00113 return 0;                                       \
00114 }
00115 
00116 
00128 int cpl_plugin_get_info(cpl_pluginlist *list)
00129 {
00130     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe );
00131     cpl_plugin *plugin = &recipe->interface;
00132 
00133     cpl_plugin_init(plugin,
00134                     CPL_PLUGIN_API,
00135                     FORS_BINARY_VERSION,
00136                     CPL_PLUGIN_TYPE_RECIPE,
00137                     "fors_normalise_flat",
00138                     "Normalise master flat spectrum",
00139                     fors_normalise_flat_description,
00140                     "Carlo Izzo",
00141                     PACKAGE_BUGREPORT,
00142     "This file is currently part of the FORS Instrument Pipeline\n"
00143     "Copyright (C) 2002-2010 European Southern Observatory\n\n"
00144     "This program is free software; you can redistribute it and/or modify\n"
00145     "it under the terms of the GNU General Public License as published by\n"
00146     "the Free Software Foundation; either version 2 of the License, or\n"
00147     "(at your option) any later version.\n\n"
00148     "This program is distributed in the hope that it will be useful,\n"
00149     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00150     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
00151     "GNU General Public License for more details.\n\n"
00152     "You should have received a copy of the GNU General Public License\n"
00153     "along with this program; if not, write to the Free Software Foundation,\n"
00154     "Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n",
00155                     fors_normalise_flat_create,
00156                     fors_normalise_flat_exec,
00157                     fors_normalise_flat_destroy);
00158 
00159     cpl_pluginlist_append(list, plugin);
00160     
00161     return 0;
00162 }
00163 
00164 
00175 static int fors_normalise_flat_create(cpl_plugin *plugin)
00176 {
00177     cpl_recipe    *recipe;
00178     cpl_parameter *p;
00179 
00180     /* 
00181      * Check that the plugin is part of a valid recipe 
00182      */
00183 
00184     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00185         recipe = (cpl_recipe *)plugin;
00186     else 
00187         return -1;
00188 
00189     /* 
00190      * Create the (empty) parameters list in the cpl_recipe object 
00191      */
00192 
00193     recipe->parameters = cpl_parameterlist_new(); 
00194 
00195     /*
00196      * Dispersion
00197      */
00198 
00199     p = cpl_parameter_new_value("fors.fors_normalise_flat.dispersion",
00200                                 CPL_TYPE_DOUBLE,
00201                                 "Expected spectral dispersion (Angstrom/pixel)",
00202                                 "fors.fors_normalise_flat",
00203                                 0.0);
00204     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion");
00205     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00206     cpl_parameterlist_append(recipe->parameters, p);
00207 
00208     /*
00209      * Start wavelength for spectral extraction
00210      */
00211 
00212     p = cpl_parameter_new_value("fors.fors_normalise_flat.startwavelength",
00213                                 CPL_TYPE_DOUBLE,
00214                                 "Start wavelength in spectral extraction",
00215                                 "fors.fors_normalise_flat",
00216                                 0.0);
00217     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength");
00218     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00219     cpl_parameterlist_append(recipe->parameters, p);
00220 
00221     /*
00222      * End wavelength for spectral extraction
00223      */
00224 
00225     p = cpl_parameter_new_value("fors.fors_normalise_flat.endwavelength",
00226                                 CPL_TYPE_DOUBLE,
00227                                 "End wavelength in spectral extraction",
00228                                 "fors.fors_normalise_flat",
00229                                 0.0);
00230     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength");
00231     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00232     cpl_parameterlist_append(recipe->parameters, p);
00233 
00234     /*
00235      * Degree of flat field fitting polynomial along spatial direction
00236      * (used for LSS data)
00237      */
00238 
00239     p = cpl_parameter_new_value("fors.fors_normalise_flat.sdegree",
00240                                 CPL_TYPE_INT,
00241                                 "Degree of flat field fitting polynomial "
00242                                 "along spatial direction (used for LSS "
00243                                 "data only)",
00244                                 "fors.fors_normalise_flat",
00245                                 4);
00246     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sdegree");
00247     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00248     cpl_parameterlist_append(recipe->parameters, p);
00249 
00250     /*
00251      * Degree of flat field fitting polynomial along dispersion direction
00252      * (used for MOS and MXU data)
00253      */
00254 
00255     p = cpl_parameter_new_value("fors.fors_normalise_flat.ddegree",
00256                                 CPL_TYPE_INT,
00257                                 "Degree of flat field fitting polynomial "
00258                                 "along dispersion direction (used for MOS "
00259                                 "and MXU data only)",
00260                                 "fors.fors_normalise_flat",
00261                                 -1);
00262     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ddegree");
00263     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00264     cpl_parameterlist_append(recipe->parameters, p);
00265 
00266     /*
00267      * Smooth box radius for flat field along dispersion direction
00268      */
00269 
00270     p = cpl_parameter_new_value("fors.fors_normalise_flat.dradius",
00271                                 CPL_TYPE_INT,
00272                                 "Smooth box radius for flat field along "
00273                                 "dispersion direction",
00274                                 "fors.fors_normalise_flat",
00275                                 10);
00276     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dradius");
00277     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00278     cpl_parameterlist_append(recipe->parameters, p);
00279 
00280     /*
00281      * Smooth box radius for flat field along spatial direction
00282      * (used for LSS data only)
00283      */
00284 
00285     p = cpl_parameter_new_value("fors.fors_normalise_flat.sradius",
00286                                 CPL_TYPE_INT,
00287                                 "Smooth box radius for flat field along "
00288                                 "spatial direction",
00289                                 "fors.fors_normalise_flat",
00290                                 10);
00291     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sradius");
00292     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00293     cpl_parameterlist_append(recipe->parameters, p);
00294 
00295     return 0;
00296 }
00297 
00298 
00307 static int fors_normalise_flat_exec(cpl_plugin *plugin)
00308 {
00309     cpl_recipe *recipe;
00310     
00311     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00312         recipe = (cpl_recipe *)plugin;
00313     else 
00314         return -1;
00315 
00316     return fors_normalise_flat(recipe->parameters, recipe->frames);
00317 }
00318 
00319 
00328 static int fors_normalise_flat_destroy(cpl_plugin *plugin)
00329 {
00330     cpl_recipe *recipe;
00331     
00332     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00333         recipe = (cpl_recipe *)plugin;
00334     else 
00335         return -1;
00336 
00337     cpl_parameterlist_delete(recipe->parameters); 
00338 
00339     return 0;
00340 }
00341 
00342 
00352 static int fors_normalise_flat(cpl_parameterlist *parlist, 
00353                                cpl_frameset *frameset)
00354 {
00355 
00356     const char *recipe = "fors_normalise_flat";
00357 
00358 
00359     /*
00360      * Input parameters
00361      */
00362 
00363     double      dispersion;
00364     double      startwavelength;
00365     double      endwavelength;
00366     int         sdegree;
00367     int         ddegree;
00368     int         sradius;
00369     int         dradius;
00370 
00371     /*
00372      * CPL objects
00373      */
00374 
00375     cpl_image        *master_flat = NULL;
00376     cpl_image        *smo_flat    = NULL;
00377     cpl_image        *coordinate  = NULL;
00378     cpl_image        *spatial     = NULL;
00379     cpl_table        *grism_table = NULL;
00380     cpl_table        *slits       = NULL;
00381     cpl_table        *polytraces  = NULL;
00382     cpl_table        *maskslits   = NULL;
00383     cpl_propertylist *header      = NULL;
00384 
00385     /*
00386      * Auxiliary variables
00387      */
00388 
00389     char        version[80];
00390     const char *master_flat_tag;
00391     const char *master_norm_flat_tag;
00392     const char *slit_location_tag;
00393     const char *curv_coeff_tag;
00394     int         mxu, mos, lss;
00395     int         nflat;
00396     int         rebin;
00397     int         nx, ny;
00398     int         nslits;
00399     int         treat_as_lss;
00400     int         i;
00401     double      reference;
00402     double     *xpos;
00403     double      mxpos;
00404 
00405     char       *instrume = NULL;
00406 
00407 
00408     cpl_msg_set_indentation(2);
00409 
00410     if (dfs_files_dont_exist(frameset))
00411         fors_normalise_flat_exit(NULL);
00412 
00413 
00414     /*
00415      * Get configuration parameters
00416      */
00417 
00418     cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe);
00419     cpl_msg_indent_more();
00420     
00421     if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1)
00422         fors_normalise_flat_exit("Too many in input: GRISM_TABLE"); 
00423 
00424     grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1);
00425 
00426     dispersion = dfs_get_parameter_double(parlist,
00427                     "fors.fors_normalise_flat.dispersion", grism_table);
00428 
00429     if (dispersion <= 0.0)
00430         fors_normalise_flat_exit("Invalid spectral dispersion value");
00431 
00432     startwavelength = dfs_get_parameter_double(parlist,
00433                     "fors.fors_normalise_flat.startwavelength", grism_table);
00434     if (startwavelength > 1.0)
00435         if (startwavelength < 3000.0 || startwavelength > 13000.0)
00436             fors_normalise_flat_exit("Invalid wavelength");
00437 
00438     endwavelength = dfs_get_parameter_double(parlist,
00439                     "fors.fors_normalise_flat.endwavelength", grism_table);
00440     if (endwavelength > 1.0) {
00441         if (endwavelength < 3000.0 || endwavelength > 13000.0)
00442             fors_normalise_flat_exit("Invalid wavelength");
00443         if (startwavelength < 1.0)
00444             fors_normalise_flat_exit("Invalid wavelength interval");
00445     }
00446 
00447     if (startwavelength > 1.0)
00448         if (endwavelength - startwavelength <= 0.0)
00449             fors_normalise_flat_exit("Invalid wavelength interval");
00450 
00451     sdegree = dfs_get_parameter_int(parlist, 
00452                                     "fors.fors_normalise_flat.sdegree", NULL);
00453     ddegree = dfs_get_parameter_int(parlist, 
00454                                     "fors.fors_normalise_flat.ddegree", NULL);
00455     sradius = dfs_get_parameter_int(parlist, 
00456                                     "fors.fors_normalise_flat.sradius", NULL);
00457     dradius = dfs_get_parameter_int(parlist, 
00458                                     "fors.fors_normalise_flat.dradius", NULL);
00459 
00460     if (sradius < 1 || dradius < 1)
00461         fors_normalise_flat_exit("Invalid smoothing box radius");
00462 
00463     cpl_table_delete(grism_table); grism_table = NULL;
00464 
00465     if (cpl_error_get_code())
00466         fors_normalise_flat_exit("Failure reading the configuration "
00467                                  "parameters");
00468 
00469 
00470     cpl_msg_indent_less();
00471     cpl_msg_info(recipe, "Check input set-of-frames:");
00472     cpl_msg_indent_more();
00473 
00474     nflat  = mxu = cpl_frameset_count_tags(frameset, "MASTER_SCREEN_FLAT_MXU");
00475     nflat += mos = cpl_frameset_count_tags(frameset, "MASTER_SCREEN_FLAT_MOS");
00476     nflat += lss = cpl_frameset_count_tags(frameset, "MASTER_SCREEN_FLAT_LSS");
00477 
00478     if (nflat == 0) {
00479         fors_normalise_flat_exit("Missing input master flat field frame");
00480     }
00481     if (nflat > 1) {
00482         cpl_msg_error(recipe, "Too many input flat frames (%d > 1)", nflat);
00483         fors_normalise_flat_exit(NULL);
00484     }
00485 
00486     if (mxu) {
00487         master_flat_tag      = "MASTER_SCREEN_FLAT_MXU";
00488         master_norm_flat_tag = "MASTER_NORM_FLAT_MXU";
00489         slit_location_tag    = "SLIT_LOCATION_MXU";
00490         curv_coeff_tag       = "CURV_COEFF_MXU";
00491     }
00492     else if (mos) {
00493         master_flat_tag      = "MASTER_SCREEN_FLAT_MOS";
00494         master_norm_flat_tag = "MASTER_NORM_FLAT_MOS";
00495         slit_location_tag    = "SLIT_LOCATION_MOS";
00496         curv_coeff_tag       = "CURV_COEFF_MOS";
00497     }
00498     else if (lss) {
00499         master_flat_tag      = "MASTER_SCREEN_FLAT_LSS";
00500         master_norm_flat_tag = "MASTER_NORM_FLAT_LSS";
00501     }
00502 
00503     header = dfs_load_header(frameset, master_flat_tag, 0);
00504 
00505     if (mos || mxu) {
00506         int nslits_out_det = 0;
00507         if (mos)
00508             maskslits = mos_load_slits_fors_mos(header, &nslits_out_det);
00509         else
00510             maskslits = mos_load_slits_fors_mxu(header);
00511 
00512         /*
00513          * Check if all slits have the same X offset: in such case,
00514          * treat the observation as a long-slit one!
00515          */
00516 
00517         treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det); 
00518 
00519         cpl_table_delete(maskslits); maskslits = NULL;
00520 
00521         if (treat_as_lss)
00522             cpl_msg_warning(recipe, "All MOS slits have the same offset: %.2f\n"
00523                             "The LSS data reduction strategy is applied!",
00524                             mxpos);
00525     }
00526 
00527     if (!(lss || treat_as_lss)) {
00528         if (cpl_frameset_count_tags(frameset, curv_coeff_tag) == 0) {
00529             cpl_msg_error(recipe, "Missing input: %s", curv_coeff_tag);
00530             fors_normalise_flat_exit(NULL);
00531         }
00532 
00533         if (cpl_frameset_count_tags(frameset, curv_coeff_tag) > 1) {
00534             cpl_msg_error(recipe, "Too many in input: %s", curv_coeff_tag);
00535             fors_normalise_flat_exit(NULL);
00536         }
00537 
00538         if (cpl_frameset_count_tags(frameset, slit_location_tag) == 0) {
00539             cpl_msg_error(recipe, "Missing input: %s", slit_location_tag);
00540             fors_normalise_flat_exit(NULL);
00541         }
00542 
00543         if (cpl_frameset_count_tags(frameset, slit_location_tag) > 1) {
00544             cpl_msg_error(recipe, "Too many in input: %s", slit_location_tag);
00545             fors_normalise_flat_exit(NULL);
00546         }
00547     }
00548 
00549     if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID"))
00550         fors_normalise_flat_exit("Input frames are not from the same grism");
00551 
00552     if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID"))
00553         fors_normalise_flat_exit("Input frames are not from the same filter");
00554 
00555     if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID"))
00556         fors_normalise_flat_exit("Input frames are not from the same chip");
00557 
00558 
00559     /*
00560      * Get the reference wavelength and the rebin factor along the
00561      * dispersion direction from the master flat frame
00562      */
00563 
00564     if (header == NULL)
00565         fors_normalise_flat_exit("Cannot load master flat frame header");
00566 
00567     instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME");
00568     if (instrume == NULL)
00569         fors_normalise_flat_exit("Missing keyword INSTRUME in master "
00570                                  "flat header");
00571 
00572     if (instrume[4] == '1')
00573         snprintf(version, 80, "%s/%s", "fors1", VERSION);
00574     if (instrume[4] == '2')
00575         snprintf(version, 80, "%s/%s", "fors2", VERSION);
00576 
00577     reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN");
00578 
00579     if (cpl_error_get_code() != CPL_ERROR_NONE)
00580         fors_normalise_flat_exit("Missing keyword ESO INS GRIS1 WLEN "
00581                                  "in master flat frame header");
00582 
00583     if (reference < 3000.0)   /* Perhaps in nanometers... */
00584         reference *= 10;
00585 
00586     if (reference < 3000.0 || reference > 13000.0) {
00587         cpl_msg_error(recipe, "Invalid central wavelength %.2f read from "
00588                       "keyword ESO INS GRIS1 WLEN in master flat header",
00589                       reference);
00590         fors_normalise_flat_exit(NULL);
00591     }
00592 
00593     cpl_msg_info(recipe, "The central wavelength is: %.2f", reference);
00594 
00595     rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX");
00596 
00597     if (cpl_error_get_code() != CPL_ERROR_NONE)
00598         fors_normalise_flat_exit("Missing keyword ESO DET WIN1 BINX "
00599                                  "in master flat header");
00600 
00601     if (rebin != 1) {
00602         dispersion *= rebin;
00603         cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the "
00604                         "working dispersion used is %f A/pixel", rebin,
00605                         dispersion);
00606     }
00607 
00608 
00609     cpl_msg_indent_less();
00610     cpl_msg_info(recipe, "Load input frames...");
00611     cpl_msg_indent_more();
00612 
00613     master_flat = dfs_load_image(frameset, master_flat_tag, 
00614                                  CPL_TYPE_FLOAT, 0, 0);
00615     if (master_flat == NULL)
00616         fors_normalise_flat_exit("Cannot load master flat field frame");
00617 
00618 
00619     cpl_msg_indent_less();
00620     cpl_msg_info(recipe, "Perform flat field normalisation...");
00621     cpl_msg_indent_more();
00622 
00623     if (lss || treat_as_lss) {
00624 
00625         /* FIXME:
00626          * The LSS data calibration is still dirty: it doesn't apply
00627          * any spatial rectification, and only in future an external
00628          * spectral curvature model would be provided in input. Here
00629          * and there temporary solutions are adpted, such as accepting
00630          * the preliminary wavelength calibration.
00631          */
00632 
00633         /*
00634          * Flat field normalisation is done directly on the master flat
00635          * field (without spatial rectification first). The spectral
00636          * curvature model may be provided in input, in future releases.
00637          */
00638 
00639         smo_flat = mos_normalise_longflat(master_flat, 
00640                                           sradius, dradius, sdegree);
00641 
00642         cpl_image_delete(smo_flat); smo_flat = NULL; /* It may be a product */
00643 
00644         if (dfs_save_image(frameset, master_flat, master_norm_flat_tag,
00645                            header, parlist, recipe, version))
00646             fors_normalise_flat_exit(NULL);
00647 
00648         cpl_propertylist_delete(header); header = NULL;
00649         cpl_image_delete(master_flat); master_flat = NULL;
00650 
00651         return 0;
00652     }
00653 
00654 
00655     /*
00656      * This is the generic MOS/MXU handling
00657      */
00658 
00659     slits = dfs_load_table(frameset, slit_location_tag, 1);
00660     if (slits == NULL)
00661         fors_normalise_flat_exit("Cannot load slits location table");
00662 
00663     polytraces = dfs_load_table(frameset, curv_coeff_tag, 1);
00664     if (slits == NULL)
00665         fors_normalise_flat_exit("Cannot load spectral curvature table");
00666 
00667     nx = cpl_image_get_size_x(master_flat);
00668     ny = cpl_image_get_size_y(master_flat);
00669 
00670     coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
00671     spatial = mos_spatial_calibration(master_flat, slits, polytraces, 
00672                                       reference,
00673                                       startwavelength, endwavelength,
00674                                       dispersion, 0, coordinate);
00675 
00676     cpl_image_delete(spatial); spatial = NULL;
00677 
00678     smo_flat = mos_normalise_flat(master_flat, coordinate, slits, polytraces,
00679                                   reference, startwavelength, endwavelength,
00680                                   dispersion, dradius, ddegree);
00681 
00682     cpl_image_delete(smo_flat); smo_flat = NULL;  /* It may be a product */
00683     cpl_image_delete(coordinate); coordinate = NULL;
00684     cpl_table_delete(polytraces); polytraces = NULL;
00685     cpl_table_delete(slits); slits = NULL;
00686 
00687     if (dfs_save_image(frameset, master_flat, master_norm_flat_tag,
00688                        header, parlist, recipe, version))
00689         fors_normalise_flat_exit(NULL);
00690 
00691     cpl_propertylist_delete(header); header = NULL;
00692     cpl_image_delete(master_flat); master_flat = NULL;
00693 
00694     return 0;
00695 }