FORS Pipeline Reference Manual 4.9.20
|
00001 /* $Id: fors_trace_flat.c,v 1.6 2013/02/28 15:16:47 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:16:47 $ 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_trace_flat_create(cpl_plugin *); 00038 static int fors_trace_flat_exec(cpl_plugin *); 00039 static int fors_trace_flat_destroy(cpl_plugin *); 00040 static int fors_trace_flat(cpl_parameterlist *, cpl_frameset *); 00041 00042 static char fors_trace_flat_description[] = 00043 "This recipe is used to trace the edges of MOS/MXU flat field slit spectra\n" 00044 "and determine the spectral curvature solution. The input master flat field\n" 00045 "image, product of the recipe fors_flat, is expected to be oriented with\n" 00046 "horizontal dispersion direction and red wavelengths on the right side.\n" 00047 "The input slits location table should be the product of the recipe\n" 00048 "fors_detect_spectra.\n" 00049 "\n" 00050 "The input master flat image is shifted one pixel down and is subtracted\n" 00051 "from the original image. The result is a vertical gradient map. Next,\n" 00052 "the negative values are forced positive, to obtain an absolute gradient\n" 00053 "map. The map is passed with a horizontal median filter, and after that\n" 00054 "the gradient peaks are traced starting from the slits positions listed\n" 00055 "in the input slits location table. The number of pixels to the left and\n" 00056 "to the right of the reference pixel is trivially derived from the specified\n" 00057 "spectral range and spectral dispersion.\n" 00058 "\n" 00059 "The output spectral curvature table contains the coefficients of the\n" 00060 "polynomial fitting of the found traces, while the output trace table\n" 00061 "contains the traced spectral edges positions in CCD (Y) coordinates for\n" 00062 "each spectrum, and their comparison with their modeling. A spatial map\n" 00063 "is also created, where to each CCD pixel is assigned the value of the\n" 00064 "spatial coordinate along the slit (in pixel). For more details please\n" 00065 "refer to the FORS Pipeline User's Manual.\n" 00066 "\n" 00067 "Note that specifying an input GRISM_TABLE will set some of the recipe\n" 00068 "configuration parameters to default values valid for a particular grism.\n" 00069 "Again, see the pipeline manual for more details.\n" 00070 "\n" 00071 "In the table below the MXU acronym can be alternatively read as MOS.\n\n" 00072 "Input files:\n\n" 00073 " DO category: Type: Explanation: Required:\n" 00074 " MASTER_SCREEN_FLAT_MXU Calib Master flat frame Y\n" 00075 " SLIT_LOCATION_DETECT_MXU Calib Slits location Y\n" 00076 " GRISM_TABLE Calib Grism table .\n\n" 00077 "Output files:\n\n" 00078 " DO category: Data type: Explanation:\n" 00079 " CURV_TRACES_MXU FITS table Flat field tracings\n" 00080 " CURV_COEFF_MXU FITS table Spectral curvature table\n" 00081 " SPATIAL_MAP_MXU FITS image Map of spatial coordinate\n\n"; 00082 00083 #define fors_trace_flat_exit(message) \ 00084 { \ 00085 if (message) cpl_msg_error(recipe, message); \ 00086 cpl_image_delete(master_flat); \ 00087 cpl_image_delete(spatial); \ 00088 cpl_image_delete(coordinate); \ 00089 cpl_table_delete(grism_table); \ 00090 cpl_table_delete(maskslits); \ 00091 cpl_table_delete(slits); \ 00092 cpl_table_delete(traces); \ 00093 cpl_table_delete(polytraces); \ 00094 cpl_propertylist_delete(header); \ 00095 cpl_msg_indent_less(); \ 00096 return -1; \ 00097 } 00098 00099 #define fors_trace_flat_exit_memcheck(message) \ 00100 { \ 00101 if (message) cpl_msg_info(recipe, message); \ 00102 printf("free master_flat (%p)\n", master_flat); \ 00103 cpl_image_delete(master_flat); \ 00104 printf("free spatial (%p)\n", spatial); \ 00105 cpl_image_delete(spatial); \ 00106 printf("free coordinate (%p)\n", coordinate); \ 00107 cpl_image_delete(coordinate); \ 00108 printf("free grism_table (%p)\n", grism_table); \ 00109 cpl_table_delete(grism_table); \ 00110 printf("free maskslits (%p)\n", maskslits); \ 00111 cpl_table_delete(maskslits); \ 00112 printf("free slits (%p)\n", slits); \ 00113 cpl_table_delete(slits); \ 00114 printf("free traces (%p)\n", traces); \ 00115 cpl_table_delete(traces); \ 00116 printf("free polytraces (%p)\n", polytraces); \ 00117 cpl_table_delete(polytraces); \ 00118 printf("free header (%p)\n", header); \ 00119 cpl_propertylist_delete(header); \ 00120 cpl_msg_indent_less(); \ 00121 return 0; \ 00122 } 00123 00124 00136 int cpl_plugin_get_info(cpl_pluginlist *list) 00137 { 00138 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe ); 00139 cpl_plugin *plugin = &recipe->interface; 00140 00141 cpl_plugin_init(plugin, 00142 CPL_PLUGIN_API, 00143 FORS_BINARY_VERSION, 00144 CPL_PLUGIN_TYPE_RECIPE, 00145 "fors_trace_flat", 00146 "Determine spectral curvature model", 00147 fors_trace_flat_description, 00148 "Carlo Izzo", 00149 PACKAGE_BUGREPORT, 00150 "This file is currently part of the FORS Instrument Pipeline\n" 00151 "Copyright (C) 2002-2010 European Southern Observatory\n\n" 00152 "This program is free software; you can redistribute it and/or modify\n" 00153 "it under the terms of the GNU General Public License as published by\n" 00154 "the Free Software Foundation; either version 2 of the License, or\n" 00155 "(at your option) any later version.\n\n" 00156 "This program is distributed in the hope that it will be useful,\n" 00157 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 00158 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 00159 "GNU General Public License for more details.\n\n" 00160 "You should have received a copy of the GNU General Public License\n" 00161 "along with this program; if not, write to the Free Software Foundation,\n" 00162 "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n", 00163 fors_trace_flat_create, 00164 fors_trace_flat_exec, 00165 fors_trace_flat_destroy); 00166 00167 cpl_pluginlist_append(list, plugin); 00168 00169 return 0; 00170 } 00171 00172 00183 static int fors_trace_flat_create(cpl_plugin *plugin) 00184 { 00185 cpl_recipe *recipe; 00186 cpl_parameter *p; 00187 00188 /* 00189 * Check that the plugin is part of a valid recipe 00190 */ 00191 00192 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00193 recipe = (cpl_recipe *)plugin; 00194 else 00195 return -1; 00196 00197 /* 00198 * Create the (empty) parameters list in the cpl_recipe object 00199 */ 00200 00201 recipe->parameters = cpl_parameterlist_new(); 00202 00203 /* 00204 * Dispersion 00205 */ 00206 00207 p = cpl_parameter_new_value("fors.fors_trace_flat.dispersion", 00208 CPL_TYPE_DOUBLE, 00209 "Expected spectral dispersion (Angstrom/pixel)", 00210 "fors.fors_trace_flat", 00211 0.0); 00212 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dispersion"); 00213 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00214 cpl_parameterlist_append(recipe->parameters, p); 00215 00216 /* 00217 * Start wavelength for spectral extraction 00218 */ 00219 00220 p = cpl_parameter_new_value("fors.fors_trace_flat.startwavelength", 00221 CPL_TYPE_DOUBLE, 00222 "Start wavelength in spectral extraction", 00223 "fors.fors_trace_flat", 00224 0.0); 00225 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "startwavelength"); 00226 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00227 cpl_parameterlist_append(recipe->parameters, p); 00228 00229 /* 00230 * End wavelength for spectral extraction 00231 */ 00232 00233 p = cpl_parameter_new_value("fors.fors_trace_flat.endwavelength", 00234 CPL_TYPE_DOUBLE, 00235 "End wavelength in spectral extraction", 00236 "fors.fors_trace_flat", 00237 0.0); 00238 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "endwavelength"); 00239 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00240 cpl_parameterlist_append(recipe->parameters, p); 00241 00242 /* 00243 * Degree of spectral curvature polynomial 00244 */ 00245 00246 p = cpl_parameter_new_value("fors.fors_trace_flat.cdegree", 00247 CPL_TYPE_INT, 00248 "Degree of spectral curvature polynomial", 00249 "fors.fors_trace_flat", 00250 0); 00251 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cdegree"); 00252 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00253 cpl_parameterlist_append(recipe->parameters, p); 00254 00255 /* 00256 * Curvature solution interpolation (for MOS-like data) 00257 */ 00258 00259 p = cpl_parameter_new_value("fors.fors_trace_flat.cmode", 00260 CPL_TYPE_INT, 00261 "Interpolation mode of curvature solution " 00262 "applicable to MOS-like data (0 = no " 00263 "interpolation, 1 = fill gaps, 2 = global " 00264 "model)", 00265 "fors.fors_trace_flat", 00266 1); 00267 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "cmode"); 00268 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV); 00269 cpl_parameterlist_append(recipe->parameters, p); 00270 00271 return 0; 00272 } 00273 00274 00283 static int fors_trace_flat_exec(cpl_plugin *plugin) 00284 { 00285 cpl_recipe *recipe; 00286 00287 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00288 recipe = (cpl_recipe *)plugin; 00289 else 00290 return -1; 00291 00292 return fors_trace_flat(recipe->parameters, recipe->frames); 00293 } 00294 00295 00304 static int fors_trace_flat_destroy(cpl_plugin *plugin) 00305 { 00306 cpl_recipe *recipe; 00307 00308 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 00309 recipe = (cpl_recipe *)plugin; 00310 else 00311 return -1; 00312 00313 cpl_parameterlist_delete(recipe->parameters); 00314 00315 return 0; 00316 } 00317 00318 00328 static int fors_trace_flat(cpl_parameterlist *parlist, 00329 cpl_frameset *frameset) 00330 { 00331 00332 const char *recipe = "fors_trace_flat"; 00333 00334 00335 /* 00336 * Input parameters 00337 */ 00338 00339 double dispersion; 00340 double startwavelength; 00341 double endwavelength; 00342 int cdegree; 00343 int cmode; 00344 00345 /* 00346 * CPL objects 00347 */ 00348 00349 cpl_image *master_flat = NULL; 00350 cpl_image *coordinate = NULL; 00351 cpl_image *spatial = NULL; 00352 cpl_table *grism_table = NULL; 00353 cpl_table *maskslits = NULL; 00354 cpl_table *slits = NULL; 00355 cpl_table *traces = NULL; 00356 cpl_table *polytraces = NULL; 00357 cpl_propertylist *header = NULL; 00358 00359 /* 00360 * Auxiliary variables 00361 */ 00362 00363 char version[80]; 00364 const char *master_flat_tag; 00365 const char *spatial_map_tag; 00366 const char *slit_detect_tag; 00367 const char *slit_location_tag; 00368 const char *curv_traces_tag; 00369 const char *curv_coeff_tag; 00370 int flat_mxu; 00371 int flat_mos; 00372 int flat_lss; 00373 int mxu, mos; 00374 int nflat; 00375 int nslits; 00376 int rebin; 00377 int nx, ny; 00378 int treat_as_lss; 00379 int i; 00380 double reference; 00381 double *xpos; 00382 double mxpos; 00383 int nslits_out_det = 0; 00384 00385 char *instrume = NULL; 00386 00387 00388 cpl_msg_set_indentation(2); 00389 00390 if (dfs_files_dont_exist(frameset)) 00391 fors_trace_flat_exit(NULL); 00392 00393 00394 /* 00395 * Get configuration parameters 00396 */ 00397 00398 cpl_msg_info(recipe, "Recipe %s configuration parameters:", recipe); 00399 cpl_msg_indent_more(); 00400 00401 if (cpl_frameset_count_tags(frameset, "GRISM_TABLE") > 1) 00402 fors_trace_flat_exit("Too many in input: GRISM_TABLE"); 00403 00404 grism_table = dfs_load_table(frameset, "GRISM_TABLE", 1); 00405 00406 dispersion = dfs_get_parameter_double(parlist, 00407 "fors.fors_trace_flat.dispersion", grism_table); 00408 00409 if (dispersion <= 0.0) 00410 fors_trace_flat_exit("Invalid spectral dispersion value"); 00411 00412 startwavelength = dfs_get_parameter_double(parlist, 00413 "fors.fors_trace_flat.startwavelength", grism_table); 00414 if (startwavelength > 1.0) 00415 if (startwavelength < 3000.0 || startwavelength > 13000.0) 00416 fors_trace_flat_exit("Invalid wavelength"); 00417 00418 endwavelength = dfs_get_parameter_double(parlist, 00419 "fors.fors_trace_flat.endwavelength", grism_table); 00420 if (endwavelength > 1.0) { 00421 if (endwavelength < 3000.0 || endwavelength > 13000.0) 00422 fors_trace_flat_exit("Invalid wavelength"); 00423 if (startwavelength < 1.0) 00424 fors_trace_flat_exit("Invalid wavelength interval"); 00425 } 00426 00427 if (startwavelength > 1.0) 00428 if (endwavelength - startwavelength <= 0.0) 00429 fors_trace_flat_exit("Invalid wavelength interval"); 00430 00431 cdegree = dfs_get_parameter_int(parlist, 00432 "fors.fors_trace_flat.cdegree", grism_table); 00433 00434 if (cdegree < 1) 00435 fors_trace_flat_exit("Invalid polynomial degree"); 00436 00437 if (cdegree > 5) 00438 fors_trace_flat_exit("Max allowed polynomial degree is 5"); 00439 00440 cmode = dfs_get_parameter_int(parlist, "fors.fors_trace_flat.cmode", NULL); 00441 00442 if (cmode < 0 || cmode > 2) 00443 fors_trace_flat_exit("Invalid curvature solution interpolation mode"); 00444 00445 cpl_table_delete(grism_table); grism_table = NULL; 00446 00447 if (cpl_error_get_code()) 00448 fors_trace_flat_exit("Failure reading the configuration parameters"); 00449 00450 00451 cpl_msg_indent_less(); 00452 cpl_msg_info(recipe, "Check input set-of-frames:"); 00453 cpl_msg_indent_more(); 00454 00455 nflat = flat_mxu = cpl_frameset_count_tags(frameset, 00456 "MASTER_SCREEN_FLAT_MXU"); 00457 nflat += flat_mos = cpl_frameset_count_tags(frameset, 00458 "MASTER_SCREEN_FLAT_MOS"); 00459 nflat += flat_lss = cpl_frameset_count_tags(frameset, 00460 "MASTER_SCREEN_FLAT_LSS"); 00461 00462 if (nflat == 0) { 00463 fors_trace_flat_exit("Missing input master flat field frame"); 00464 } 00465 if (nflat > 1) { 00466 cpl_msg_error(recipe, "Too many input flat frames (%d > 1)", nflat); 00467 fors_trace_flat_exit(NULL); 00468 } 00469 00470 mxu = mos = 0; 00471 00472 if (flat_mxu) { 00473 mxu = 1; 00474 master_flat_tag = "MASTER_SCREEN_FLAT_MXU"; 00475 slit_detect_tag = "SLIT_LOCATION_DETECT_MXU"; 00476 slit_location_tag = "SLIT_LOCATION_MXU"; 00477 curv_traces_tag = "CURV_TRACES_MXU"; 00478 curv_coeff_tag = "CURV_COEFF_MXU"; 00479 spatial_map_tag = "SPATIAL_MAP_MXU"; 00480 } 00481 else if (flat_mos) { 00482 mos = 1; 00483 master_flat_tag = "MASTER_SCREEN_FLAT_MOS"; 00484 slit_detect_tag = "SLIT_LOCATION_DETECT_MOS"; 00485 slit_location_tag = "SLIT_LOCATION_MOS"; 00486 curv_traces_tag = "CURV_TRACES_MOS"; 00487 curv_coeff_tag = "CURV_COEFF_MOS"; 00488 spatial_map_tag = "SPATIAL_MAP_MOS"; 00489 } 00490 else if (flat_lss) { 00491 fors_trace_flat_exit("LSS spectra are not traceable: use this recipe " 00492 "just for MOS/MXU data."); 00493 } 00494 00495 if (cpl_frameset_count_tags(frameset, slit_detect_tag) == 0) { 00496 cpl_msg_error(recipe, "Missing required input: %s", slit_detect_tag); 00497 fors_trace_flat_exit(NULL); 00498 } 00499 00500 if (cpl_frameset_count_tags(frameset, slit_detect_tag) > 1) { 00501 cpl_msg_error(recipe, "Too many in input: %s", slit_detect_tag); 00502 fors_trace_flat_exit(NULL); 00503 } 00504 00505 if (!dfs_equal_keyword(frameset, "ESO INS GRIS1 ID")) 00506 fors_trace_flat_exit("Input frames are not from the same grism"); 00507 00508 if (!dfs_equal_keyword(frameset, "ESO INS FILT1 ID")) 00509 fors_trace_flat_exit("Input frames are not from the same filter"); 00510 00511 if (!dfs_equal_keyword(frameset, "ESO DET CHIP1 ID")) 00512 fors_trace_flat_exit("Input frames are not from the same chip"); 00513 00514 00515 /* 00516 * Get the reference wavelength and the rebin factor along the 00517 * dispersion direction from the master flat frame 00518 */ 00519 00520 header = dfs_load_header(frameset, master_flat_tag, 0); 00521 00522 if (header == NULL) 00523 fors_trace_flat_exit("Cannot load master flat frame header"); 00524 00525 instrume = (char *)cpl_propertylist_get_string(header, "INSTRUME"); 00526 if (instrume == NULL) 00527 fors_trace_flat_exit("Missing keyword INSTRUME in master flat header"); 00528 00529 if (instrume[4] == '1') 00530 snprintf(version, 80, "%s/%s", "fors1", VERSION); 00531 if (instrume[4] == '2') 00532 snprintf(version, 80, "%s/%s", "fors2", VERSION); 00533 00534 reference = cpl_propertylist_get_double(header, "ESO INS GRIS1 WLEN"); 00535 00536 if (cpl_error_get_code() != CPL_ERROR_NONE) 00537 fors_trace_flat_exit("Missing keyword ESO INS GRIS1 WLEN " 00538 "in master flat frame header"); 00539 00540 if (reference < 3000.0) /* Perhaps in nanometers... */ 00541 reference *= 10; 00542 00543 if (reference < 3000.0 || reference > 13000.0) { 00544 cpl_msg_error(recipe, "Invalid central wavelength %.2f read from " 00545 "keyword ESO INS GRIS1 WLEN in master flat header", 00546 reference); 00547 fors_trace_flat_exit(NULL); 00548 } 00549 00550 cpl_msg_info(recipe, "The central wavelength is: %.2f", reference); 00551 00552 rebin = cpl_propertylist_get_int(header, "ESO DET WIN1 BINX"); 00553 00554 if (cpl_error_get_code() != CPL_ERROR_NONE) 00555 fors_trace_flat_exit("Missing keyword ESO DET WIN1 BINX " 00556 "in master flat header"); 00557 00558 if (rebin != 1) { 00559 dispersion *= rebin; 00560 cpl_msg_warning(recipe, "The rebin factor is %d, and therefore the " 00561 "working dispersion used is %f A/pixel", rebin, 00562 dispersion); 00563 } 00564 00565 00566 /* 00567 * Check if all slits have the same X offset: in such case, abort! 00568 */ 00569 00570 if (mos) 00571 maskslits = mos_load_slits_fors_mos(header, &nslits_out_det); 00572 else 00573 maskslits = mos_load_slits_fors_mxu(header); 00574 00575 treat_as_lss = fors_mos_is_lss_like(maskslits, nslits_out_det); 00576 00577 if (treat_as_lss) { 00578 cpl_msg_error(recipe, "All slits have the same offset: %.2f mm\n" 00579 "Spectra are not traceable: the LSS data reduction\n" 00580 "strategy must be applied.", mxpos); 00581 fors_trace_flat_exit(NULL); 00582 } 00583 00584 cpl_table_delete(maskslits); maskslits = NULL; 00585 00586 00587 cpl_msg_indent_less(); 00588 cpl_msg_info(recipe, "Load input frames..."); 00589 cpl_msg_indent_more(); 00590 00591 master_flat = dfs_load_image(frameset, master_flat_tag, 00592 CPL_TYPE_FLOAT, 0, 0); 00593 if (master_flat == NULL) 00594 fors_trace_flat_exit("Cannot load master flat field frame"); 00595 00596 slits = dfs_load_table(frameset, slit_detect_tag, 1); 00597 if (slits == NULL) 00598 fors_trace_flat_exit("Cannot load slits location table"); 00599 00600 00601 cpl_msg_indent_less(); 00602 cpl_msg_info(recipe, "Determining spectral curvature..."); 00603 cpl_msg_indent_more(); 00604 00605 cpl_msg_info(recipe, "Tracing master flat field spectra edges..."); 00606 traces = mos_trace_flat(master_flat, slits, reference, 00607 startwavelength, endwavelength, dispersion); 00608 00609 if (!traces) 00610 fors_trace_flat_exit("Tracing failure"); 00611 00612 cpl_msg_info(recipe, "Fitting flat field spectra edges..."); 00613 polytraces = mos_poly_trace(slits, traces, cdegree); 00614 00615 if (!polytraces) 00616 fors_trace_flat_exit("Trace fitting failure"); 00617 00618 if (cmode) { 00619 cpl_msg_info(recipe, "Computing global spectral curvature model..."); 00620 mos_global_trace(slits, polytraces, cmode); 00621 } 00622 00623 if (dfs_save_table(frameset, traces, curv_traces_tag, NULL, parlist, 00624 recipe, version)) 00625 fors_trace_flat_exit(NULL); 00626 00627 cpl_table_delete(traces); traces = NULL; 00628 00629 nx = cpl_image_get_size_x(master_flat); 00630 ny = cpl_image_get_size_y(master_flat); 00631 coordinate = cpl_image_new(nx, ny, CPL_TYPE_FLOAT); 00632 00633 spatial = mos_spatial_calibration(master_flat, slits, polytraces, 00634 reference, 00635 startwavelength, endwavelength, 00636 dispersion, 0, coordinate); 00637 00638 cpl_image_delete(master_flat); master_flat = NULL; 00639 cpl_image_delete(spatial); spatial = NULL; 00640 00641 if (dfs_save_image(frameset, coordinate, spatial_map_tag, header, 00642 parlist, recipe, version)) 00643 fors_trace_flat_exit(NULL); 00644 00645 cpl_image_delete(coordinate); coordinate = NULL; 00646 cpl_propertylist_delete(header); header = NULL; 00647 00648 if (dfs_save_table(frameset, slits, slit_location_tag, NULL, 00649 parlist, recipe, version)) 00650 fors_trace_flat_exit(NULL); 00651 00652 cpl_table_delete(slits); slits = NULL; 00653 00654 if (dfs_save_table(frameset, polytraces, curv_coeff_tag, NULL, 00655 parlist, recipe, version)) 00656 fors_trace_flat_exit(NULL); 00657 00658 cpl_table_delete(polytraces); polytraces = NULL; 00659 00660 return 0; 00661 }