UVES Pipeline Reference Manual  5.4.0
uves_orderpos_body.c
1 /* *
2  * This file is part of the ESO UVES Pipeline *
3  * Copyright (C) 2004,2005 European Southern Observatory *
4  * *
5  * This library is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the Free Software *
17  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA *
18  * */
19 
20 /*
21  * $Author: amodigli $
22  * $Date: 2013-08-08 13:36:46 $
23  * $Revision: 1.52 $
24  * $Name: not supported by cvs2svn $
25  * $Log: not supported by cvs2svn $
26  * Revision 1.51 2013/07/01 15:36:52 amodigli
27  * Rename DEBUG to debug_mode to remove compiler error on some platforms (that name is reserved to special compiler options)
28  *
29  * Revision 1.50 2012/11/28 09:45:26 amodigli
30  * changed default minthresh for FIBER mode back to its original value: 0.2 that shows to be more robust
31  *
32  * Revision 1.49 2011/08/25 08:18:04 amodigli
33  * changed default minthresh to 0.01 only in flames_cal_orderpos, and flames_obs_redchain uves_orderpos_body.c
34  *
35  * Revision 1.48 2010/12/13 08:21:36 amodigli
36  * fixed mem leak
37  *
38  * Revision 1.47 2010/09/27 15:22:34 amodigli
39  * removed 'norders' parameter
40  *
41  * Revision 1.46 2010/09/24 09:32:04 amodigli
42  * put back QFITS dependency to fix problem spot by NRI on FIBER mode (with MIDAS calibs) data
43  *
44  * Revision 1.44 2010/06/09 08:50:23 amodigli
45  * In case USE_GUESS_TAB==2, make check if temporary order table start order numbering from 1. If not correct it appropriately before calling uves_locate_orders. Then put back orders numbering as it was. This to prevent a problem possibly found in case USE_GUESS_TAB==2 and an input guess table is provided with order numbering not starting at 1
46  *
47  * Revision 1.43 2010/05/11 10:49:09 amodigli
48  * Fixed typo on param description
49  *
50  * Revision 1.42 2010/05/06 14:55:00 amodigli
51  * increased min allowed val of backsubgrid to 10 and changed default of kappa to 4
52  *
53  * Revision 1.41 2009/10/29 17:16:54 amodigli
54  * added param to specify if red cdd is new/old in call to uves_get_badpix
55  *
56  * Revision 1.40 2009/02/18 12:06:06 amodigli
57  * fixed mem leak
58  *
59  * Revision 1.39 2008/09/29 06:57:52 amodigli
60  * add #include <string.h>
61  *
62  * Revision 1.38 2008/05/01 09:51:42 amodigli
63  * fixed compiler warnings
64  *
65  * Revision 1.37 2008/02/15 12:43:49 amodigli
66  * allow lower/upper chip for parameter process_chip
67  *
68  * Revision 1.36 2007/12/17 07:41:41 amodigli
69  * added some descriptors to pipe products
70  *
71  * Revision 1.35 2007/12/03 08:00:19 amodigli
72  * added HIERARCH keys to 'debug' product
73  *
74  * Revision 1.34 2007/11/13 16:19:17 amodigli
75  * product order table in case of FIBER mode is now FIB_ORD_TAB_x
76  *
77  * Revision 1.33 2007/10/23 06:48:57 amodigli
78  * Master bias is subtracted if provided
79  *
80  * Revision 1.32 2007/10/05 16:01:45 amodigli
81  * using proces_chip parameter to process or not a given RED chip
82  *
83  * Revision 1.31 2007/09/19 14:13:02 amodigli
84  * Fibre-Order-Definition-Results-->Single-Fibre-Order-Definition-Results
85  *
86  * Revision 1.30 2007/08/23 15:14:14 amodigli
87  * fixed DFS04255: the value of ymax in the search of orders was improperly set
88  *
89  * Revision 1.29 2007/08/21 13:08:26 jmlarsen
90  * Removed irplib_access module, largely deprecated by CPL-4
91  *
92  * Revision 1.28 2007/08/02 15:21:06 amodigli
93  * added parameter --use_guess_tab and possibility to use the input guess table as it was in MIDAS (default option). Kept optional also current behaviour
94  *
95  * Revision 1.27 2007/07/17 12:40:04 jmlarsen
96  * Fixed bug in update of DEFPOL variables
97  *
98  * Revision 1.26 2007/06/28 09:17:40 jmlarsen
99  * Write polynomial in MIDAS format if FLAMES
100  *
101  * Revision 1.25 2007/06/22 09:28:51 jmlarsen
102  * Changed interface of uves_save_image
103  *
104  * Revision 1.24 2007/06/06 08:17:33 amodigli
105  * replace tab with 4 spaces
106  *
107  * Revision 1.23 2007/05/22 14:34:32 jmlarsen
108  * Removed unnecessary includes
109  *
110  * Revision 1.22 2007/04/24 16:45:17 amodigli
111  * changed interface of calls to uves_load_ordertable to match new interface
112  *
113  * Revision 1.21 2007/04/24 12:50:29 jmlarsen
114  * Replaced cpl_propertylist -> uves_propertylist which is much faster
115  *
116  * Revision 1.20 2007/04/17 09:34:38 jmlarsen
117  * Parametrize the assumption about consecutive orders (for FLAMES support)
118  *
119  * Revision 1.19 2007/04/12 12:01:44 jmlarsen
120  * Skip Hough transform if guess table is provided
121  *
122  * Revision 1.18 2007/04/03 06:29:21 amodigli
123  * changed interface to uves_load_ordertable
124  *
125  * Revision 1.17 2007/03/28 14:02:18 jmlarsen
126  * Removed unused parameter
127  *
128  * Revision 1.16 2007/03/28 11:38:55 jmlarsen
129  * Killed MIDAS flag, removed dead code
130  *
131  * Revision 1.15 2006/12/11 12:34:58 jmlarsen
132  * Fixed QC bugs
133  *
134  * Revision 1.14 2006/12/11 11:06:44 jmlarsen
135  * Read QC chip name from input header
136  *
137  * Revision 1.13 2006/12/07 08:24:21 jmlarsen
138  * Factored some common QC parameters
139  *
140  * Revision 1.12 2006/12/01 12:26:51 jmlarsen
141  * Factored out FLAMES plate-id code
142  *
143  * Revision 1.11 2006/11/16 14:12:21 jmlarsen
144  * Changed undefined trace number from 0 to -1, to support zero as an actual trace number
145  *
146  * Revision 1.10 2006/11/16 09:49:25 jmlarsen
147  * Fixed doxygen bug
148  *
149  * Revision 1.9 2006/11/15 15:02:14 jmlarsen
150  * Implemented const safe workarounds for CPL functions
151  *
152  * Revision 1.7 2006/11/15 14:04:08 jmlarsen
153  * Removed non-const version of parameterlist_get_first/last/next which is
154  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
155  *
156  * Revision 1.6 2006/11/13 12:46:26 jmlarsen
157  * Added doc.
158  *
159  * Revision 1.5 2006/11/06 15:19:41 jmlarsen
160  * Removed unused include directives
161  *
162  * Revision 1.4 2006/10/26 14:03:33 jmlarsen
163  * Fixed position of const modifier
164  *
165  * Revision 1.3 2006/10/25 07:22:59 jmlarsen
166  * Fixed wrong parameter context: hough -> trace
167  *
168  * Revision 1.2 2006/10/24 14:42:26 jmlarsen
169  * Added plate number logging
170  *
171  * Revision 1.34 2006/10/17 12:33:02 jmlarsen
172  * Added semicolon at UVES_RECIPE_DEFINE invocation
173  *
174  * Revision 1.33 2006/10/09 13:01:13 jmlarsen
175  * Use macro to define recipe interface functions
176  *
177  * Revision 1.32 2006/09/20 12:53:57 jmlarsen
178  * Replaced stringcat functions with uves_sprintf()
179  *
180  * Revision 1.31 2006/09/19 14:31:10 jmlarsen
181  * uves_insert_frame(): use bitmap to specify which image statistics keywords must be computed
182  *
183  * Revision 1.30 2006/09/19 06:55:11 jmlarsen
184  * Changed interface of uves_frameset to optionally write image statistics kewwords
185  *
186  * Revision 1.29 2006/08/24 11:36:37 jmlarsen
187  * Write recipe start/stop time to header
188  *
189  * Revision 1.28 2006/08/18 13:35:42 jmlarsen
190  * Fixed/changed QC parameter formats
191  *
192  * Revision 1.27 2006/08/11 14:56:05 amodigli
193  * removed Doxygen warnings
194  *
195  * Revision 1.26 2006/08/07 11:35:35 jmlarsen
196  * Disabled parameter environment variable mode
197  *
198  * Revision 1.25 2006/07/14 12:19:28 jmlarsen
199  * Support multiple QC tests per product
200  *
201  * Revision 1.24 2006/07/03 14:20:39 jmlarsen
202  * Exclude bad pixels from order tracing
203  *
204  * Revision 1.23 2006/07/03 13:09:24 amodigli
205  * adjusted description display layout
206  *
207  * Revision 1.22 2006/07/03 12:46:34 amodigli
208  * updated description
209  *
210  * Revision 1.21 2006/06/22 12:13:10 amodigli
211  * removed ESO prefix
212  *
213  * Revision 1.20 2006/06/22 06:44:06 amodigli
214  * added some QC param
215  *
216  * Revision 1.19 2006/06/16 08:25:34 jmlarsen
217  * Do the order tracing on non-median filtered frame
218  *
219  * Revision 1.18 2006/06/13 11:57:02 jmlarsen
220  * Check that calibration frames are from the same chip ID
221  *
222  * Revision 1.17 2006/06/08 11:40:50 amodigli
223  * added check to have output order table as input guess, if provided
224  *
225  * Revision 1.16 2006/06/08 08:42:53 jmlarsen
226  * Added support for computing Hough transform on image subwindow
227  *
228  * Revision 1.15 2006/06/07 13:06:28 jmlarsen
229  * Changed doxygen tag addtogroup -> defgroup
230  *
231  * Revision 1.14 2006/06/07 09:01:28 amodigli
232  * added some doc
233  *
234  * Revision 1.13 2006/06/06 08:40:10 jmlarsen
235  * Shortened max line length
236  *
237  * Revision 1.12 2006/05/09 15:42:00 amodigli
238  * added QC log
239  *
240  * Revision 1.11 2006/05/08 15:41:32 amodigli
241  * added order table chopping (commented out)
242  *
243  * Revision 1.10 2006/05/05 13:55:17 jmlarsen
244  * Minor doc update
245  *
246  * Revision 1.9 2006/04/20 10:47:39 amodigli
247  * added qclog
248  *
249  * Revision 1.8 2006/04/06 09:48:15 amodigli
250  * changed uves_frameset_insert interface to have QC log
251  *
252  * Revision 1.7 2006/04/06 08:46:40 jmlarsen
253  * Changed default polynomial degrees to auto
254  *
255  * Revision 1.6 2006/03/24 14:04:14 jmlarsen
256  * Changed background subtraction sample density default parameter value
257  *
258  * Revision 1.5 2006/03/09 10:53:41 jmlarsen
259  * Changed default bivariate degrees to MIDAS values
260  *
261  * Revision 1.4 2006/03/03 13:54:11 jmlarsen
262  * Changed syntax of check macro
263  *
264  * Revision 1.3 2006/02/28 09:15:22 jmlarsen
265  * Minor update
266  *
267  * Revision 1.2 2006/02/21 14:26:54 jmlarsen
268  * Minor changes
269  *
270  * Revision 1.1 2006/02/03 07:46:30 jmlarsen
271  * Moved recipe implementations to ./uves directory
272  *
273  * Revision 1.63 2006/01/19 08:47:24 jmlarsen
274  * Inserted missing doxygen end tag
275  *
276  * Revision 1.62 2006/01/05 14:31:31 jmlarsen
277  * Checking for guess DRS table before guess order table
278  *
279  * Revision 1.61 2005/12/20 16:10:32 jmlarsen
280  * Added some documentation
281  *
282  * Revision 1.60 2005/12/19 16:17:55 jmlarsen
283  * Replaced bool -> int
284  *
285  */
286 #ifdef HAVE_CONFIG_H
287 # include <config.h>
288 #endif
289 
290 /*----------------------------------------------------------------------------*/
294 /*----------------------------------------------------------------------------*/
295 
296 /*-----------------------------------------------------------------------------
297  Includes
298  -----------------------------------------------------------------------------*/
299 
300 #include <uves_orderpos_body.h>
301 
302 #include <uves_orderpos_hough.h>
303 #include <uves_orderpos_follow.h>
304 
305 #include <uves_physmod_chop_otab.h>
306 #include <uves_corrbadpix.h>
307 #include <uves_utils.h>
308 #include <uves_recipe.h>
309 #include <uves_parameters.h>
310 #include <uves_backsub.h>
311 #include <uves_pfits.h>
312 #include <uves_dfs.h>
313 #include <uves_qclog.h>
314 #include <uves_utils_wrappers.h>
315 #include <uves_utils_cpl.h>
316 #include <uves_error.h>
317 #include <uves_msg.h>
318 
319 #include <cpl.h>
320 
321 #include <float.h>
322 #include <string.h>
323 /*-----------------------------------------------------------------------------
324  Functions prototypes
325  -----------------------------------------------------------------------------*/
326 /* compute qclog */
327 static void uves_orderpos_qclog(cpl_table* table,
328  bool flames,
329  int pord,
330  int dord,
331  int samples_per_order,
332  uves_propertylist* rhead,
333  enum uves_chip chip,
334  cpl_table* qclog);
335 
338 /*-----------------------------------------------------------------------------
339  Exported variables
340  -----------------------------------------------------------------------------*/
341 
342 const char * const uves_orderpos_desc_short = "Defines echelle order positions";
343 const char * const uves_orderpos_desc =
344 "The recipe defines the order positions in an echelle image. The orders are\n"
345 "initially detected by means of a Hough transformation, the orders are then \n"
346 "traced, and the positions are finally fitted with a global polynomial.\n"
347 "\n"
348 "Expected input frames are narrow flat fields, ORDER_FLAT_xxx, or standard \n"
349 "stars, STANDARD_xxx, where xxx is 'BLUE' or 'RED', and optionally for each \n"
350 "chip a DRS setup table (DRS_TABLE_BLUE, DRS_TABLE_REDL, DRS_TABLE_REDU) or \n"
351 "guess order table (ORDER_GUESS_TAB_BLUE, ORDER_GUESS_TAB_REDL, \n"
352 "ORDER_GUESS_TAB_REDU, \n"
353 "or, for backward compatibility, ORDER_TABLE_BLUE, ORDER_TABLE_REDL, \n"
354 "ORDER_TABLE_REDU). The recipe processes only the first raw frame found.\n"
355 "\n"
356 "Output is one (or two if input is a red frame) order table(s) \n"
357 "(UVES: ORDER_TABLE_(BLUE|REDL|REDU); FLAMES: FIB_ORDEF_(REDL|REDU) contaning\n"
358 "the columns:\n"
359 "X : Position along x\n"
360 "Order : Relative order number\n"
361 "Y : Order line centroid location\n"
362 "Yfit : The fitted order location\n"
363 "dY : Uncertainty of Y\n"
364 "dYfit_Square : Variance of Yfit\n"
365 "Residual : Y - Yfit\n"
366 "Residual_Square : Residual^2\n"
367 "OrderRMS : Root mean squared residual of initial\n"
368 " one-dimensional linear fit of order\n"
369 "\n"
370 "The bivariate fit polynomial itself is stored in table extension no. 2.\n"
371 "The 3rd table extension contains a table that defines the active fibre traces\n"
372 "and their positions (for support of FLAMES/UVES)\n";
373 
374 
375 /*-----------------------------------------------------------------------------
376  Functions code
377  -----------------------------------------------------------------------------*/
378 /*----------------------------------------------------------------------------*/
385 /*----------------------------------------------------------------------------*/
386 int
387 uves_orderpos_define_parameters_body(cpl_parameterlist *parameters,
388  const char *recipe_id)
389 {
390  const char *subcontext;
391  double min_thresh=0.2;
392 
393  /*****************
394  * General *
395  *****************/
396 
397  if (uves_define_global_parameters(parameters) != CPL_ERROR_NONE)
398  {
399  return -1;
400  }
401 
402  /*****************
403  * Preprocessing *
404  *****************/
405 
406  subcontext = "preproc";
407 
408  /* Use of Guess sol */
409  uves_par_new_enum("use_guess_tab",
410  CPL_TYPE_INT,
411  "If a Guess order table is provided this parameter set how it is used:"
412  "0: No usage, "
413  "1: use it to set lower/upper Y raws where order are searched "
414  "2: the order table try to fully match the guess",
415  1, 3, 0, 1, 2);
416 
417 
418 
419  /* Radx, Rady */
420  uves_par_new_range("radx",
421  CPL_TYPE_INT,
422  "Half X size of median filtering window",
423  2, 0, INT_MAX);
424 
425  uves_par_new_range("rady",
426  CPL_TYPE_INT,
427  "Half Y size of median filtering window",
428  1, 0, INT_MAX);
429 
430  /* Mmethod */
431  uves_par_new_enum("mmethod",
432  CPL_TYPE_STRING,
433  "Background subtraction method. If equal "
434  "to 'median' the background is sampled using "
435  "the median of a sub-window. If 'minimum', "
436  "the minimum sub-window value is used. If "
437  "'no', no background subtraction is done.",
438  "median", /* Default */
439  3, /* Number of options */
440  "median", "minimum", "no"); /* List of options */
441 
442  /* Backsubgrid */
443  uves_par_new_range("backsubgrid",
444  CPL_TYPE_INT,
445  "Number of grid points (in x- and y-direction) "
446  "used to estimate "
447  "the background (mode=poly).",
448  50, 10, INT_MAX);
449 
450  /* Backsubradiusy */
451  uves_par_new_range("backsubradiusy",
452  CPL_TYPE_INT,
453  "The height (in pixels) of the background "
454  "sampling window is (2*radiusy + 1). "
455  "This parameter is not corrected for binning.",
456  2, 0, INT_MAX);
457 
458  /* Backsubkappa */
459  uves_par_new_range("backsubkappa",
460  CPL_TYPE_DOUBLE,
461  "The value of kappa in the one-sided kappa-sigma "
462  "clipping used to "
463  "estimate the background (mode=poly).",
464  4.0, 0.0, DBL_MAX);
465 
466  /* Backsubdegx, backsubdegy */
467  uves_par_new_range("backsubdegx",
468  CPL_TYPE_INT,
469  "Degree (in x) of polynomial used "
470  "to estimate the background (mode=poly).",
471  2, 1, INT_MAX);
472 
473  uves_par_new_range("backsubdegy",
474  CPL_TYPE_INT,
475  "Degree (in y) of polynomial used "
476  "to estimate the background (mode=poly).",
477  2, 1, INT_MAX);
478 
479  /*******************
480  * Hough detection *
481  *******************/
482  subcontext = "hough";
483 
484  /* Samplewidth */
485  uves_par_new_range("samplewidth",
486  CPL_TYPE_INT,
487  "Separation of sample traces "
488  "(used by Hough transform) in input image",
489  50, 1, INT_MAX);
490 
491  /* Minslope, Maxslope */
492  uves_par_new_range("minslope",
493  CPL_TYPE_DOUBLE,
494  "Minimum possible line slope. This should "
495  "be the 'physical' slope on the chip, "
496  "i.e. not taking binning factors into "
497  "account, which is handled by the recipe",
498  0.0, 0.0, DBL_MAX);
499 
500  uves_par_new_range("maxslope",
501  CPL_TYPE_DOUBLE,
502  "Maximum possible line slope",
503  0.2, 0.0, DBL_MAX);
504 
505  /* Sloperes */
506  uves_par_new_range("sloperes",
507  CPL_TYPE_INT,
508  "Resolution (width in pixels) of Hough space",
509  120, 1, INT_MAX);
510 
511  /* Norders */
512  /* decided to temporally remove this as only option 0 works
513  later one need to fix the behaviour for this parameter
514 
515  uves_par_new_range("norders",
516  CPL_TYPE_INT,
517  "Number of echelle orders to detect. If "
518  "set to 0 the predicted number of orders will "
519  "be read from the guess order table. If no "
520  "guess order table is given, the recipe will "
521  "try to autodetect the number of orders. If "
522  "the raw frame is a red chip and this parameter "
523  "is specified, the given value will be used "
524  "for both red chips",
525  0, 0, INT_MAX);
526 
527  */
528  /* Pthres */
529  uves_par_new_range("pthres",
530  CPL_TYPE_DOUBLE,
531  "In automatic mode, or if the number of orders "
532  "to detect is read from a guess table, the detection "
533  "of new lines stops when the intensity of a candidate "
534  "line drops to less than 'pthres' times the intensity "
535  "of the previous detection. "
536 /* Text applicable only if 'norders' parameter is present
537  "Otherwise - i.e. if the "
538  "number of orders to detect was specified by setting "
539  "the 'norders' parameters - this parameter is "
540  "ignored."
541 */
542  ,
543  0.2, 0.0, 1.0);
544 
545  /*******************
546  * Order tracing *
547  *******************/
548  subcontext = "trace";
549 
550  /* Tracestep */
551  uves_par_new_range("tracestep",
552  CPL_TYPE_INT,
553  "The step size used when tracing the orders",
554  10, 1, INT_MAX);
555 
556  /* Minthres */
557  min_thresh=0.2;
558  uves_par_new_range("minthresh",
559  CPL_TYPE_DOUBLE,
560  "The minimum threshold value is (min + "
561  "minthres*(max - min)). Here 'min' "
562  "and 'max' are the lowest and highest pixel "
563  "values in the central bin of the order",
564  min_thresh, 0.0, 1.0);
565 
566  /* Maxgap */
567  uves_par_new_range("maxgap",
568  CPL_TYPE_DOUBLE,
569  "If the order line drops below detection "
570  "threshold, the order tracing algorithm "
571  "will try to jump a gap of maximum size 'maxgap' "
572  "multiplied by the image width",
573  .2, 0.0, 1.0);
574 
575  /***************
576  * Rejection *
577  ***************/
578 
579  subcontext = "reject";
580 
581  /* Maxrms */ /* In uves/midas default is 3.5 */
582  uves_par_new_range("maxrms",
583  CPL_TYPE_DOUBLE,
584  "When fitting the orders with straight lines, "
585  "this is the maximum allowed RMS relative to "
586  "the median RMS of all orders",
587  100.0, 0.0, DBL_MAX);
588 
589  /* In MIDAS, defpol=2,3 is used which is not optimal
590  but faster than (-1,-1) */
591  /* Defpol1 */
592  uves_par_new_range("defpol1",
593  CPL_TYPE_INT,
594  "The degree of the bivarite fit (cross "
595  "dispersion direction). If negative, "
596  "the degree is optimized to give the best fit",
597  -1,
598  -1, INT_MAX);
599 
600  /* Defpol2 */
601  uves_par_new_range("defpol2",
602  CPL_TYPE_INT,
603  "The degree of the bivarite fit (order number). "
604  "If negative, "
605  "the degree is optimized to give the best fit",
606  -1,
607  -1, INT_MAX);
608 
609  /* Kappa */
610  uves_par_new_range("kappa",
611  CPL_TYPE_DOUBLE,
612  "Used for kappa-sigma clipping of the final "
613  "polynomial fit. If negative, no clipping is done",
614  4.0, -2.0, DBL_MAX);
615 
616  return (cpl_error_get_code() != CPL_ERROR_NONE);
617 }
618 
619 /*----------------------------------------------------------------------------*/
669 /*----------------------------------------------------------------------------*/
670 static cpl_table *
671 uves_orderpos_process_chip(const cpl_image *raw_image,
672  uves_propertylist *raw_header,
673  const uves_propertylist *rotated_header,
674  enum uves_chip chip,
675  int binx, int biny,
676  /* General */
677  bool debug_mode,
678  /* Preprocessing */
679  int USE_GUESS_TAB,
680  int RADX,
681  int RADY,
682  background_measure_method BM_METHOD,
683  int BACKSUBGRID,
684  int BACKSUBRADIUSY,
685  double BACKSUBKAPPA,
686  int BACKSUBDEGX,
687  int BACKSUBDEGY,
688  /* Hough transform */
689  int SAMPLEWIDTH,
690  double MINSLOPE,
691  double MAXSLOPE,
692  int SLOPERES,
693  int NORDERS,
694  bool norders_is_guess,
695  double PTHRES,
696  /* Order following */
697  int TRACESTEP,
698  double MINTHRESH,
699  double MAXGAP,
700  /* Rejection */
701  double MAXRMS,
702  int *DEFPOL1,
703  int *DEFPOL2,
704  double KAPPA,
705  /* Output */
706  polynomial **bivariate_fit,
707  int *norders,
708  cpl_table* guess_table)
709 {
710  /* Result */
711  cpl_table *tracetable = NULL;
712 
713  cpl_image *noise = NULL; /* Image defining the noise
714  of the current image */
715  cpl_image *back_subbed = NULL;
716  cpl_image *hough_trans = NULL;
717  polynomial *guess_locations = NULL;
718 
719  /* Debug objects */
720  cpl_image *inputlines = NULL; /* Hough solution drawn
721  on top of input image */
722  cpl_table *ordertable = NULL; /* A preliminary order table
723  containing one row per order */
724  cpl_image *hough_original = NULL;
725  int abs_ord_min=0;
726  int abs_ord_max=0;
727  int badpixels_marked = 0;
728  int ymin = 0;
729  int ymax = 0;
730  int ord_min=0;
731  bool red_ccd_is_new=0;
732  check_nomsg(red_ccd_is_new=uves_ccd_is_new(raw_header));
733 
734  check( back_subbed = cpl_image_duplicate(raw_image), "Error duplicating image");
735  ymin = 1;
736  ymax = cpl_image_get_size_y(back_subbed);
737  uves_msg("===============");
738  /* uves_msg("guess order tab=%p",guess_table); */
739  /* Calculate the basic order table */
740  if(guess_table != NULL)
741  {
742  if(USE_GUESS_TAB == 1) {
743  int ymin_guess=ymin;
744  int ymax_guess=ymax;
745  int omin=0;
746  int omax=0;
747  cpl_table* tmp_tbl=NULL;
748 
749  uves_msg("Use input guess order table to define the detector area");
750  uves_msg("where to locate orders");
751 
752 
753  tmp_tbl=cpl_table_duplicate(guess_table);
754  uves_physmod_chop_otab(raw_header,chip,&tmp_tbl,"Order",&omin,&omax);
755 
756  uves_msg("On Guess Found %d orders.",omax-omin+1);
757  if(omax < cpl_table_get_column_max(guess_table,"Order")) {
758  uves_free_table(&tmp_tbl);
759  check(tmp_tbl=uves_extract_table_rows(guess_table,"Order",
760  CPL_EQUAL_TO,omax+1),
761  "Error selecting Order");
762 
763  check(ymax_guess=(int)cpl_table_get_column_min(tmp_tbl,"Yfit")-1,
764  "error getting ymax_guess");
765  uves_free_table(&tmp_tbl);
766  }
767 
768  if(omin > cpl_table_get_column_min(guess_table,"Order")) {
769  uves_free_table(&tmp_tbl);
770  check(tmp_tbl=uves_extract_table_rows(guess_table,"Order",
771  CPL_EQUAL_TO,omin-1),
772  "Error selecting Order");
773 
774  check(ymin_guess=(int)cpl_table_get_column_max(tmp_tbl,"Yfit")+1,
775  "error getting ymin_guess");
776 
777  uves_free_table(&tmp_tbl);
778  }
779  ymin = (ymin_guess>ymin) ? ymin_guess : ymin;
780  ymax = (ymax_guess<ymax) ? ymax_guess : ymax;
781 
782  uves_msg("Serching them in the region [ymin,ymax]=[%d,%d]",ymin,ymax);
783  uves_free_table(&tmp_tbl);
784 
785 
786  } else if (USE_GUESS_TAB == 2) {
787 
788  // Create a table with order lines in the same format as the
789  // Hough transform would do it, i.e. intersept + slope for each order.
790 
791  int minorder = uves_round_double(
792  cpl_table_get_column_min(guess_table, "Order"));
793  int maxorder = uves_round_double(
794  cpl_table_get_column_max(guess_table, "Order"));
795  int nx = cpl_image_get_size_x(back_subbed);
796  int order;
797 
798 
799  uves_msg("Create a table with order lines in the same format as the");
800  uves_msg("Hough transform would do it, ");
801  uves_msg("i.e. intersept + slope for each order.");
802 
803  {
804  double kappa = 4;
805  int max_degree = 6;
806  double min_rms = 0.1; /* pixels */
807  double mse;
809  guess_table,
810  "X", "Order", "Yfit", NULL,
811  NULL, NULL, NULL,
812  &mse, NULL, NULL,
813  kappa,
814  max_degree, max_degree, min_rms, -1,
815  false,
816  NULL, NULL, -1, NULL),
817  "Could not fit polynomial to provided table");
818 
819  uves_msg("Provided table contains orders %d - %d. RMS = %.3f pixels",
820  minorder, maxorder, sqrt(mse));
821  }
822 
823 
824 
825  ordertable = cpl_table_new(maxorder - minorder + 1);
826  cpl_table_new_column(ordertable, "Order", CPL_TYPE_INT);
827  cpl_table_new_column(ordertable, "Intersept", CPL_TYPE_DOUBLE);
828  cpl_table_new_column(ordertable, "Slope", CPL_TYPE_DOUBLE);
829  cpl_table_new_column(ordertable, "Spacing", CPL_TYPE_INT);
830 
831  for (order = minorder; order <= maxorder; order++)
832  {
833  int row = order - minorder;
834  double slope =
835  uves_polynomial_derivative_2d(guess_locations, nx/2, order, 1);
836  double intersept = uves_polynomial_evaluate_2d(guess_locations, nx/2, order)
837  - slope*(nx/2);
838  int spacing =
839  uves_round_double(uves_polynomial_derivative_2d(
840  guess_locations, nx/2, order, 2));
841 
842  cpl_table_set_int (ordertable, "Order", row, order);
843  cpl_table_set_double(ordertable, "Slope", row, slope);
844  cpl_table_set_int (ordertable, "Spacing", row, spacing);
845  cpl_table_set_double(ordertable, "Intersept", row, intersept);
846  }
847 
848  }
849 
850  }
851  if( (guess_table == NULL) || (USE_GUESS_TAB != 2) )
852  {
853 
854  /* Detect orders from scratch */
855  uves_msg("Detect orders from scratch ");
856 
857 
858 
859  /* Remove bad/hot pixels with a median filter.
860  * This is needed for the Hough transform, but
861  * we trace the orders on the raw image (gives better fit).
862  */
863  {
864  bool extrapolate_border = true; /* This is needed to avoid a sudden
865  intensity increase near the image
866  borders (which will confuse the Hough
867  transform) */
868 
869  uves_msg("Applying %dx%d median filter", RADX*2+1, RADY*2+1);
870  check( uves_filter_image_median(&back_subbed, RADX, RADY, extrapolate_border),
871  "Could not filter image");
872  }
873 
874  /* Subtract background */
875  uves_msg("Subtracting background (grid sampling)");
876 
877  check( uves_backsub_poly(back_subbed,
878  NULL, NULL, /* Order locations are unknown */
879  BM_METHOD,
880  BACKSUBGRID,
881  BACKSUBRADIUSY,
882  BACKSUBDEGX,
883  BACKSUBDEGY,
884  BACKSUBKAPPA),
885  "Could not subtract background");
886 
887  check( ordertable = uves_hough(back_subbed,
888  ymin, ymax,
889  NORDERS, norders_is_guess,
890  SAMPLEWIDTH,
891  PTHRES,
892  MINSLOPE,
893  MAXSLOPE,
894  SLOPERES,
895  true, /* Consecutive orders? */
896  &hough_trans,
897  &hough_original),
898  "Could not locate echelle orders");
899 
900  if (debug_mode)
901  {
902 
904  "^ESO ", 0),
905  "Error copying hieararch keys");
906 
907  check( uves_save_image_local("Hough transform", "hough",
908  hough_original, chip, -1, -1,
909  rotated_header, true),
910  "Error saving hough image");
911 
912  check( uves_save_image_local("Hough transform (peaks deleted)",
913  "hough_delete", hough_trans,
914  chip, -1, -1, rotated_header,
915  true),
916  "Error saving hough image");
917 
918  /* For debugging, draw Hough detected orders
919  (straight lines) on top of the input image */
920  check( inputlines = cpl_image_duplicate(raw_image),
921  "Could not duplicate image");
922  check( uves_draw_orders(ordertable, inputlines),
923  "Could not draw hough orders on image");
924 
925  check( uves_save_image_local("Lines detected by Hough transform",
926  "inputlines", inputlines, chip, -1, -1, rotated_header, true),
927  "Error saving hough image");
928 
929  uves_free_image(&inputlines);
930  }
931 
932  /* Clean up */
933  uves_free_image(&hough_trans);
934  uves_free_image(&hough_original);
935  }
936  /* Initial order detection done */
937 
938  /* Subtract background, but this time sample the interorder space */
939  check(( uves_free_image(&back_subbed),
940  back_subbed = cpl_image_duplicate(raw_image)),
941  "Error duplicating image");
942 
943  uves_msg("Subtracting background (inter-order sampling)");
944  check( uves_backsub_poly(back_subbed,
945  ordertable, NULL,
946  BM_METHOD,
947  BACKSUBGRID,
948  BACKSUBRADIUSY,
949  BACKSUBDEGX,
950  BACKSUBDEGY,
951  BACKSUBKAPPA),
952  "Could not subtract background");
953 
954  /* Create noise image (readout + photonic noise)
955  * We need to do this *after* background subtraction,
956  * because we cannot distinguish bias from scattered light
957  * (if master bias was explicitly subtracted, we should
958  * define the noise model before background subtraction)
959  */
960  check( noise = uves_define_noise(back_subbed, raw_header, 1, chip),
961  "Error creating noise image");
962 
963  if (debug_mode)
964  {
965  /* Save pre-processed (cropped, rotated, median filtered,
966  backgr. subtracted) input image */
967  check( uves_save_image_local("Pre-processed raw frame", "preproc",
968  back_subbed, chip, -1, -1, rotated_header, true),
969  "Error saving image");
970 
971  /* Save noise of pre-processed input image */
972  check( uves_save_image_local("Noise of pre-processed image",
973  "preproc_noise",
974  noise, chip, -1, -1, rotated_header, true),
975  "Error saving image");
976  }
977 
978  /* Mark bad pixels */
979  check( badpixels_marked =
980  uves_correct_badpix_all(back_subbed, /* MIDAS uses raw_image here */
981  raw_header,
982  chip,
983  binx, biny,
984  true, /* Mark, don't interpolate bad pixels */
985  red_ccd_is_new
986  ),
987  "Error marking bad pixels");
988 
989  uves_msg("%d pixels marked as bad", badpixels_marked);
990 
991  /* Trace the orders
992  (using the background subtracted image or not if MIDAS) */
993  uves_msg("norders=%d",*norders);
994  if(USE_GUESS_TAB==2) {
995  ord_min=cpl_table_get_column_min(ordertable,"Order");
996  if (ord_min>1) {
997  cpl_table_subtract_scalar(ordertable,"Order",ord_min-1);
998  }
999  }
1000 
1001  check( tracetable = uves_locate_orders(back_subbed, /* MIDAS uses raw_image here */
1002  noise,
1003  ordertable,
1004  TRACESTEP,
1005  MINTHRESH,
1006  MAXGAP,
1007  MAXRMS,
1008  DEFPOL1, DEFPOL2,
1009  KAPPA,
1010  bivariate_fit,
1011  norders), "Could not trace orders");
1012 
1013  if(USE_GUESS_TAB==2) {
1014  if (ord_min>1) {
1015  cpl_table_add_scalar(ordertable,"Order",ord_min-1);
1016  }
1017  }
1018 
1019  if (false)
1020  /* This is a workaround for a broken wavecal recipe in the MIDAS
1021  pipeline. There is no reason to do this in the CPL pipeline,
1022  where the wavecal recipe is able to deal with partial orders */
1023  {
1024  check(uves_physmod_chop_otab(raw_header,chip,&tracetable,"Order",
1025  &abs_ord_min,&abs_ord_max),
1026  "Could not run uves_physmod_chop_otab on trace order table");
1027  }
1028 
1029 
1030  /* add QC log */
1031 
1032 
1033  /* Save basic info about orders */
1034  if (debug_mode) check( uves_save_table_local("Basic order table", "basic",
1035  ordertable, chip, -1, -1, raw_header, NULL),
1036  "Error saving table");
1037 
1038  cleanup:
1039  uves_free_image(&back_subbed);
1040  uves_free_image(&noise);
1041  uves_free_image(&hough_trans);
1042  uves_polynomial_delete(&guess_locations);
1043 
1044  /* Debug objects */
1045  uves_free_image(&hough_original);
1046  uves_free_image(&inputlines);
1047  uves_free_table(&ordertable);
1048 
1049  return tracetable;
1050 }
1051 
1052 /*----------------------------------------------------------------------------*/
1067 /*----------------------------------------------------------------------------*/
1068 void
1069 uves_orderpos_exe_body(cpl_frameset *frames,
1070  bool flames,
1071  const char *recipe_id,
1072  const cpl_parameterlist *parameters,
1073  const char *starttime)
1074 {
1075  /*
1076  * Variables that will contain the values of the recipe parameters
1077  */
1078 
1079  /* General */
1080  bool debug_mode;
1081  /* Preprocessing */
1082  int USE_GUESS_TAB, RADX, RADY;
1083  background_measure_method BM_METHOD;
1084  int BACKSUBGRID;
1085  int BACKSUBRADIUSY;
1086  double BACKSUBKAPPA;
1087  int BACKSUBDEGX;
1088  int BACKSUBDEGY;
1089  /* Hough transform */
1090  int SAMPLEWIDTH;
1091  double MINSLOPE, MAXSLOPE;
1092  int SLOPERES;
1093  int NORDERS=0;
1094  double PTHRES;
1095  /* Order following */
1096  int TRACESTEP;
1097  double MINTHRESH;
1098  double MAXGAP;
1099  /* Rejection */
1100  double MAXRMS;
1101  int DEFPOL1_par; /* Recipe parameter */
1102  int DEFPOL2_par;
1103  double KAPPA;
1104  const char* PROCESS_CHIP=NULL;
1105 
1106  /* Master bias */
1107  cpl_image *master_bias = NULL;
1108  uves_propertylist *master_bias_header = NULL;
1109 
1110 
1111  /* Input image */
1112  cpl_image *raw_image[2] = {NULL, NULL};
1113  uves_propertylist *raw_header[2] = {NULL, NULL};
1114  uves_propertylist *rotated_header[2] = {NULL, NULL};
1115  cpl_image *raw_image_int = NULL;
1116 
1117  /* Input guess table */
1118  uves_propertylist *guess_header = NULL;
1119  cpl_table *guess_table = NULL;
1120 
1121  /* Output table */
1122  cpl_table *tracetable = NULL;
1123  polynomial *bivariate_fit = NULL;
1124  cpl_table *traces = NULL; /* FLAMES/UVES compatibility */
1125  uves_propertylist *product_header = NULL;
1126  cpl_table* qclog[2] = {NULL, NULL};
1127 
1128  /* Local variables */
1129  const char *raw_filename = "";
1130  char *product_filename = NULL;
1131  int ord_predict = 0;
1132  bool norders_is_guess = false; /* Was norders read from guess table? */
1133  bool blue;
1134  enum uves_chip chip;
1135  int binx = 0;
1136  int biny = 0;
1137 
1138 
1139  const char *guess_filename = "";
1140  const char *chip_name = "";
1141  const char *master_bias_filename = "";
1142 
1143  int raw_index =0;
1144  int norders = 0; /* Number of orders detected */
1145 
1146  int DEFPOL1 = 0;
1147  int DEFPOL2 = 0;
1148 
1149  bool load_guess = false;
1150 
1151  int plate_no;
1152 
1153  int samples_per_order =0;
1154  char values[80];
1155 
1156  int i=0;
1157  int j=0;
1158 
1159 
1160  /* Read recipe parameters */
1161  {
1162  /* General */
1163  check( uves_get_parameter(parameters, NULL, "uves", "debug", CPL_TYPE_BOOL, &debug_mode),
1164  "Could not read parameter");
1165  check( uves_get_parameter(parameters, NULL, "uves", "process_chip", CPL_TYPE_STRING, &PROCESS_CHIP),
1166  "Could not read parameter");
1167  uves_string_toupper((char*)PROCESS_CHIP);
1168 
1169  /* Preprocessing */
1170  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.use_guess_tab",
1171  CPL_TYPE_INT , &USE_GUESS_TAB), "Could not read parameter");
1172  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.radx",
1173  CPL_TYPE_INT , &RADX), "Could not read parameter");
1174  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.rady",
1175  CPL_TYPE_INT , &RADY), "Could not read parameter");
1176 
1177  check( BM_METHOD = uves_get_bm_method(parameters, recipe_id, "preproc"),
1178  "Could not read background measuring method");
1179 
1180  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.backsubgrid",
1181  CPL_TYPE_INT , &BACKSUBGRID),
1182  "Could not read parameter");
1183  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.backsubradiusy",
1184  CPL_TYPE_INT, &BACKSUBRADIUSY), "Could not read parameter");
1185  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.backsubkappa",
1186  CPL_TYPE_DOUBLE,&BACKSUBKAPPA), "Could not read parameter");
1187  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.backsubdegx",
1188  CPL_TYPE_INT , &BACKSUBDEGX), "Could not read parameter");
1189  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.backsubdegy",
1190  CPL_TYPE_INT , &BACKSUBDEGY), "Could not read parameter");
1191  /* Hough */
1192  check( uves_get_parameter(parameters, NULL, recipe_id, "hough.samplewidth" ,
1193  CPL_TYPE_INT , &SAMPLEWIDTH), "Could not read parameter");
1194  check( uves_get_parameter(parameters, NULL, recipe_id, "hough.minslope" ,
1195  CPL_TYPE_DOUBLE, &MINSLOPE ), "Could not read parameter");
1196  check( uves_get_parameter(parameters, NULL, recipe_id, "hough.maxslope" ,
1197  CPL_TYPE_DOUBLE, &MAXSLOPE ), "Could not read parameter");
1198  check( uves_get_parameter(parameters, NULL, recipe_id, "hough.sloperes" ,
1199  CPL_TYPE_INT , &SLOPERES ), "Could not read parameter");
1200 /* hough.norders parameter has been temporally removed
1201  check( uves_get_parameter(parameters, NULL, recipe_id, "hough.norders" ,
1202  CPL_TYPE_INT , &NORDERS ), "Could not read parameter");
1203 */
1204  check( uves_get_parameter(parameters, NULL, recipe_id, "hough.pthres" ,
1205  CPL_TYPE_DOUBLE, &PTHRES ), "Could not read parameter");
1206  /* Tracing */
1207  check( uves_get_parameter(parameters, NULL, recipe_id, "trace.tracestep" ,
1208  CPL_TYPE_INT , &TRACESTEP ), "Could not read parameter");
1209  check( uves_get_parameter(parameters, NULL, recipe_id, "trace.minthresh" ,
1210  CPL_TYPE_DOUBLE, &MINTHRESH ), "Could not read parameter");
1211  check( uves_get_parameter(parameters, NULL, recipe_id, "trace.maxgap" ,
1212  CPL_TYPE_DOUBLE, &MAXGAP ), "Could not read parameter");
1213  /* Reject */
1214  check( uves_get_parameter(parameters, NULL, recipe_id, "reject.maxrms" ,
1215  CPL_TYPE_DOUBLE, &MAXRMS ), "Could not read parameter");
1216  check( uves_get_parameter(parameters, NULL, recipe_id, "reject.defpol1" ,
1217  CPL_TYPE_INT , &DEFPOL1_par ), "Could not read parameter");
1218  check( uves_get_parameter(parameters, NULL, recipe_id, "reject.defpol2" ,
1219  CPL_TYPE_INT , &DEFPOL2_par), "Could not read parameter");
1220  check( uves_get_parameter(parameters, NULL, recipe_id, "reject.kappa" ,
1221  CPL_TYPE_DOUBLE, &KAPPA ), "Could not read parameter");
1222 
1223  /* The range of parameters have already been checked by the caller */
1224  /* Do some additional checking */
1225  assure( MINSLOPE < MAXSLOPE , CPL_ERROR_ILLEGAL_INPUT,
1226  "Minimum slope must be smaller than maximum slope (min = %f; max = %f)",
1227  MINSLOPE, MAXSLOPE);
1228  if (MAXSLOPE > 0.5){
1229  uves_msg_warning("Hough transformation might fail when searching for "
1230  "lines with slope larger than 0.5 (maxslope = %f)", MAXSLOPE);
1231  }
1232 
1233  if (DEFPOL1_par >= 6 || DEFPOL2_par >= 6)
1234  {
1235  uves_msg_warning("Polynomial fitting might be unstable with "
1236  "polynomial degrees higher than 5");
1237  }
1238 
1239  }
1240 
1241  /* Load raw image and header, and identify input frame as red or blue */
1242  check( uves_load_orderpos(frames,
1243  flames,
1244  &raw_filename, raw_image,
1245  raw_header, rotated_header, &blue), "Error loading raw frame");
1246 
1247  /* Normalize the range of slopes to match the binning of the input image */
1248  check (binx = uves_pfits_get_binx(raw_header[0]),
1249  "Could not read x binning factor from input header");
1250  check (biny = uves_pfits_get_biny(raw_header[0]),
1251  "Could not read y binning factor from input header");
1252  /* If, for instance, BINX = 2, the slope of a line in the input frame is
1253  twice the slope of the line on the (unbinned) chip, and generally we need
1254  to change SLOPE := BINX/BINY * SLOPE, when going from unbinned to binned
1255  data.
1256  Additionally, when rotating a UVES frame into standard orientation, x- and y-
1257  directions are swapped, so the parameters MINSLOPE and MAXSLOPE must be
1258  multiplied by BINY/BINX to correct for binning. */
1259  MINSLOPE = (MINSLOPE*biny)/binx;
1260  MAXSLOPE = (MAXSLOPE*biny)/binx;
1261 
1262  ord_predict = NORDERS;
1263 
1264  /* Loop over one or two chips */
1265  for (chip = uves_chip_get_first(blue);
1266  chip != UVES_CHIP_INVALID;
1267  chip = uves_chip_get_next(chip))
1268  {
1269 
1270  if(strcmp(PROCESS_CHIP,"REDU") == 0) {
1271  chip = uves_chip_get_next(chip);
1272  }
1273 
1274 
1275 
1276  raw_index = uves_chip_get_index(chip);
1277  norders = 0; /* Number of orders detected */
1278 
1279  DEFPOL1 = DEFPOL1_par;
1280  DEFPOL2 = DEFPOL2_par;
1281 
1282  uves_msg("Processing %s chip in '%s'",
1283  uves_chip_tostring_upper(chip), raw_filename);
1284 
1285  check_nomsg( chip_name = uves_pfits_get_chipid(raw_header[raw_index], chip));
1286 
1287  uves_msg_debug("Binning = %dx%d", binx, biny);
1288 
1289  /* If user didn't specify number of orders, then
1290  * Load the DRS-table (MIDAS), or if not present,
1291  * load the guess order table, or if not present,
1292  * auto-detect number of orders
1293  */
1294  if (NORDERS == 0)
1295  {
1296  /* The number of orders to detect will
1297  be read from input guess table (if available),
1298  and it is just a guess: */
1299  norders_is_guess = true;
1300 
1301  uves_free_propertylist(&guess_header);
1302 
1303  if (cpl_frameset_find(frames, UVES_DRS_SETUP(flames, chip)) != NULL)
1304  {
1305  uves_msg_low("No guess order table found");
1306 
1307  check( uves_load_drs(frames, flames, chip_name, &guess_filename,
1308  &guess_header, chip),
1309  "Error loading setup table");
1310 
1311  uves_msg("Using setup table in '%s'", guess_filename);
1312 
1313  check( ord_predict = uves_pfits_get_ordpred(guess_header),
1314  "Could not read predicted number "
1315  "of orders from DRS table header");
1316  }
1317  else if (cpl_frameset_find(frames,
1318  UVES_ORDER_TABLE(flames, chip)) != NULL ||
1319  cpl_frameset_find(frames,
1320  UVES_GUESS_ORDER_TABLE(flames, chip)) != NULL)
1321  {
1322  load_guess = (
1323  cpl_frameset_find(frames,
1324  UVES_GUESS_ORDER_TABLE(flames, chip))
1325  != NULL);
1326 
1327  uves_free_table(&guess_table);
1328 
1329  check( uves_load_ordertable(
1330  frames,
1331  flames,
1332  chip_name,
1333  &guess_filename,
1334  &guess_table,
1335  &guess_header,
1336  NULL,
1337  NULL, /* Don't read order polynomial */
1338  NULL, /* Don't read fibre traces */
1339  NULL, NULL, /* oshift, yshift */
1340  NULL, NULL, /* fibre_pos,fibre_mask */
1341  chip,
1342  load_guess),
1343  "Error loading guess order table");
1344 
1345  uves_msg("Using guess order table in '%s'", guess_filename);
1346 
1347  check( ord_predict = uves_pfits_get_ordpred(guess_header),
1348  "Could not read predicted number of orders from "
1349  "guess order table header");
1350  }
1351  else
1352  {
1353  uves_msg("No guess table found");
1354  }
1355  }
1356  else
1357  {
1358  /* The user has specified the number of orders to detect.
1359  * The user is always right, so don't allow the
1360  * detection algorithm to detect fewer orders.
1361  */
1362  norders_is_guess = false;
1363  }
1364 
1365  /* Load master bias, set pointer to NULL if not present */
1366  uves_free_image(&master_bias);
1367  uves_free_propertylist(&master_bias_header);
1368  if (cpl_frameset_find(frames, UVES_MASTER_BIAS(chip)) != NULL)
1369  {
1370  uves_free_image(&master_bias);
1371  uves_free_propertylist(&master_bias_header);
1372  check( uves_load_mbias(frames,
1373  chip_name,
1374  &master_bias_filename, &master_bias,
1375  &master_bias_header, chip),
1376  "Error loading master bias");
1377 
1378  uves_msg_low("Using master bias in '%s'", master_bias_filename);
1379  cpl_image_subtract(raw_image[raw_index],master_bias);
1380 
1381  }
1382  else
1383  {
1384  uves_msg_low("No master bias in SOF. Bias subtraction not done");
1385  }
1386 
1387  /* Execute macro steps */
1388  check((uves_free_table (&tracetable),
1389  uves_polynomial_delete(&bivariate_fit),
1390  tracetable = uves_orderpos_process_chip(
1391  raw_image[raw_index],
1392  raw_header[raw_index],
1393  rotated_header[raw_index],
1394  chip, binx, biny,
1395  debug_mode,
1396  USE_GUESS_TAB,
1397  RADX, RADY,
1398  BM_METHOD,
1399  BACKSUBGRID,
1400  BACKSUBRADIUSY,
1401  BACKSUBKAPPA,
1402  BACKSUBDEGX, BACKSUBDEGY,
1403  SAMPLEWIDTH,
1404  MINSLOPE, MAXSLOPE,
1405  SLOPERES,
1406  ord_predict,
1407  norders_is_guess,
1408  PTHRES,
1409  TRACESTEP,
1410  MINTHRESH,
1411  MAXGAP,
1412  MAXRMS,
1413  &DEFPOL1,
1414  &DEFPOL2,
1415  KAPPA,
1416  &bivariate_fit,
1417  &norders,
1418  guess_table)),
1419  "Error processing chip");
1420 
1421  /* Finished. Save the products */
1422  uves_msg("Saving products...");
1423 
1424  /* QC parameters should go here.
1425  Other mandatory keywords (FITS + dfs) are
1426  automatically added. */
1427  uves_free_propertylist(&product_header);
1428  product_header = uves_propertylist_new();
1429 
1430  /* Write number of detected orders */
1431  check( uves_pfits_set_ordpred( product_header, norders),
1432  "Error writing number of detected orders");
1433 
1434  if (flames)
1435  {
1436 
1437  check( plate_no = uves_flames_pfits_get_plateid(raw_header[raw_index]),
1438  "Error reading plate id");
1439 
1440  uves_flames_pfits_set_newplateid(product_header, plate_no);
1441  }
1442 
1443  /* Save order trace table */
1444  {
1445  samples_per_order =
1446  cpl_image_get_size_x(raw_image[raw_index]) / TRACESTEP;
1447 
1448  uves_qclog_delete(&qclog[0]);
1449  qclog[0] = uves_qclog_init(raw_header[raw_index], chip);
1450  check_nomsg( uves_orderpos_qclog(tracetable,
1451  flames,
1452  ord_predict,
1453  norders,
1454  samples_per_order,
1455  raw_header[raw_index],chip,qclog[0]));
1456  }
1457 
1458  if (flames) {
1459  /* Write polynomial in MIDAS format, as expected
1460  by flames_cal_prep_sff_ofpos */
1461 
1462  /* Only COEFFI(6) and COEFFI(7) are used */
1463  snprintf(values, 80, "-1 -1 -1 -1 -1 %d %d", DEFPOL1, DEFPOL2);
1464 
1465  uves_propertylist_append_string(product_header,
1466  "HISTORY", "'COEFFI','I*4'");
1467  uves_propertylist_append_string(product_header,
1468  "HISTORY", values);
1469  uves_propertylist_append_string(product_header,
1470  "HISTORY", " ");
1471 
1472  /* Polynomial coeffients */
1473  uves_propertylist_append_string(product_header,
1474  "HISTORY", "'COEFFD','R*8'");
1475  {
1476 
1477  for (j = 0; j <= DEFPOL2; j++) {
1478  for (i = 0; i <= DEFPOL1; i++) {
1479  snprintf(values, 80, "%g",
1480  uves_polynomial_get_coeff_2d(bivariate_fit, i, j));
1481  uves_propertylist_append_string(product_header,
1482  "HISTORY", values);
1483  }
1484  }
1485  }
1486  uves_propertylist_append_string(product_header,
1487  "HISTORY", " ");
1488 
1489  /* Min - max values */
1490  uves_propertylist_append_string(product_header,
1491  "HISTORY", "'COEFFR','R*4'");
1492  snprintf(values, 80, "%g %g",
1493  cpl_table_get_column_min(tracetable, "X"),
1494  cpl_table_get_column_max(tracetable, "X"));
1495  uves_propertylist_append_string(product_header,
1496  "HISTORY", values);
1497 
1498  snprintf(values, 80, "%g %g",
1499  cpl_table_get_column_min(tracetable, "Order"),
1500  cpl_table_get_column_max(tracetable, "Order"));
1501  uves_propertylist_append_string(product_header,
1502  "HISTORY", values);
1503 
1504  uves_propertylist_append_string(product_header,
1505  "HISTORY", " ");
1506  }
1507 
1508  check(( cpl_free(product_filename),
1509  product_filename = uves_order_table_filename(chip),
1510  uves_frameset_insert(frames,
1511  tracetable,
1512  CPL_FRAME_GROUP_PRODUCT,
1513  CPL_FRAME_TYPE_TABLE,
1514  CPL_FRAME_LEVEL_INTERMEDIATE,
1515  product_filename,
1516  UVES_ORD_TAB(flames, chip),
1517  raw_header[raw_index],
1518  product_header,
1519  NULL,
1520  parameters,
1521  recipe_id,
1522  PACKAGE "/" PACKAGE_VERSION,
1523  qclog,
1524  starttime, true, 0)),
1525  "Could not add trace table %s to frameset", product_filename);
1526  uves_qclog_delete(&qclog[0]);
1527  uves_msg("Trace table %s added to frameset", product_filename);
1528 
1529  /* Save polynomial in next extension (don't add header keywords) */
1530  check( uves_save_polynomial(bivariate_fit, product_filename, NULL),
1531  "Could not write polynomial to file %s", product_filename);
1532 
1533  /* Original comment:
1534  For compatibility with FLAMES/UVES, create the extension defining
1535  that there is only one trace which has zero offset, and that
1536  this trace is enabled.
1537 
1538  Update after the implementation of FLAMES support:
1539  This extension is not used by FLAMES and is therefore redundant.
1540  But for simplicity, keep it as it was
1541  */
1542  {
1543 
1544  uves_free_table(&traces);
1545  traces = uves_ordertable_traces_new();
1546  uves_ordertable_traces_add(traces, 0, 0.0, 1);
1547 
1548  check( cpl_table_save(traces,
1549  NULL, /* Primary header,
1550  ignored when mode is IO_EXTEND */
1551  NULL, /* Extension header */
1552  product_filename,/* This file already exists
1553  (or an error occurs) */
1554  CPL_IO_EXTEND), /* Append to existing file */
1555  "Error appending table to file '%s'", product_filename);
1556  }
1557  /* Finished saving order table */
1558 
1559  if (flames) {
1560  /* Make two calibration frames out of the input frame */
1561 
1562  /* Save as integer */
1563  uves_free_image(&raw_image_int);
1564  raw_image_int = cpl_image_cast(raw_image[raw_index],
1565  CPL_TYPE_INT);
1566 
1567  check(( cpl_free(product_filename),
1568  product_filename = uves_ordef_filename(chip),
1569  uves_frameset_insert(frames,
1570  raw_image_int,
1571  CPL_FRAME_GROUP_PRODUCT,
1572  CPL_FRAME_TYPE_IMAGE,
1573  CPL_FRAME_LEVEL_INTERMEDIATE,
1574  product_filename,
1575  FLAMES_ORDEF(flames, chip),
1576  raw_header[raw_index], /* raw header */
1577  rotated_header[raw_index], /* output header */
1578  NULL,
1579  parameters,
1580  recipe_id,
1581  PACKAGE "/" PACKAGE_VERSION,
1582  NULL, /* No QC */
1583  starttime, false,
1584  CPL_STATS_MIN | CPL_STATS_MAX)),
1585  "Could not add raw frame %s to frameset", product_filename);
1586 
1587  uves_msg("Raw frame %s added to frameset", product_filename);
1588  uves_free_image(&raw_image_int);
1589  }
1590 
1591  if(strcmp(PROCESS_CHIP,"REDL") == 0) {
1592  chip = uves_chip_get_next(chip);
1593  }
1594 
1595 
1596  } /* For each chip */
1597 
1598  cleanup:
1599  /* Raw */
1600  uves_free_image(&(raw_image[0]));
1601  uves_free_image(&(raw_image[1]));
1602  uves_free_image(&raw_image_int);
1603  uves_free_propertylist(&(raw_header[0]));
1604  uves_free_propertylist(&(raw_header[1]));
1605  uves_free_propertylist(&(rotated_header[0]));
1606  uves_free_propertylist(&(rotated_header[1]));
1607 
1608  /* Master bias */
1609  uves_free_image(&master_bias);
1610  uves_free_propertylist(&master_bias_header);
1611 
1612  /* Calibration */
1613  uves_free_propertylist(&guess_header);
1614  uves_free_table (&guess_table);
1615 
1616  /* Product */
1617  uves_qclog_delete(&qclog[0]);
1618  uves_free_table (&tracetable);
1619  uves_polynomial_delete(&bivariate_fit);
1620  uves_free_table (&traces);
1621  uves_free_propertylist(&product_header);
1622  cpl_free(product_filename);
1623 
1624  return;
1625 }
1636 static void uves_orderpos_qclog(cpl_table* table,
1637  bool flames,
1638  int pord,
1639  int dord,
1640  int samples_per_order,
1641  uves_propertylist* raw_header,
1642  enum uves_chip chip,
1643  cpl_table* qclog)
1644 {
1645  const char* chip_name;
1646  const char* grat_name;
1647  const char* ins_mode;
1648  double grat_wlen=0;
1649 
1650  uves_qclog_add_string(qclog,
1651  "QC TEST1 ID",
1652  flames ?
1653  "Single-Fibre-Order-Definition-Results" :
1654  "Order-Definition-Results",
1655  "Name of QC test",
1656  "%s");
1657 
1658  check_nomsg( chip_name=uves_pfits_get_chip_name(raw_header,chip) );
1659  /* chip_name = UVES_QC_CHIP_VAL(chip); */
1660 
1661  uves_qclog_add_string(qclog,
1662  uves_remove_string_prefix(UVES_CHIP_NAME(chip),"ESO "),
1663  chip_name,
1664  "Grating unique ID",
1665  "%s");
1666 
1667 
1668  check_nomsg(grat_name=uves_pfits_get_gratname(raw_header,chip));
1669 
1670 
1671 
1672  uves_qclog_add_string(qclog,
1673  uves_remove_string_prefix(UVES_GRATNAME(chip),"ESO "),
1674  grat_name,
1675  "Cross disperser ID",
1676  "%s");
1677 
1678 
1679  check_nomsg(ins_mode=uves_pfits_get_insmode(raw_header));
1680  uves_qclog_add_string(qclog,
1681  uves_remove_string_prefix(UVES_INSMODE,"ESO "),
1682  ins_mode,
1683  "Instrument mode used.",
1684  "%s");
1685 
1686 
1687  check_nomsg(grat_wlen=uves_pfits_get_gratwlen(raw_header,chip));
1688  uves_qclog_add_double(qclog,
1689  uves_remove_string_prefix(UVES_GRATWLEN(chip),"ESO "),
1690  grat_wlen,
1691  "Grating central wavelength [nm]",
1692  "%.1f");
1693 
1694  uves_msg_debug("chip_name=%s grat_name=%s ins_mode=%s grat_wlen=%f",
1695  chip_name,grat_name,ins_mode,grat_wlen);
1696 
1697  uves_qclog_add_double(qclog,
1698  "QC ORD RESIDMIN",
1699  cpl_table_get_column_min(table,"Residual"),
1700  "min resid in ord def",
1701  "%8.4f");
1702 
1703  uves_qclog_add_double(qclog,
1704  "QC ORD RESIDMAX",
1705  cpl_table_get_column_max(table,"Residual"),
1706  "max resid in ord def",
1707  "%8.4f");
1708 
1709  uves_qclog_add_double(qclog,
1710  "QC ORD RESIDAVG",
1711  cpl_table_get_column_mean(table,"Residual"),
1712  "mean resid in ord def",
1713  "%8.4f");
1714 
1715  uves_qclog_add_double(qclog,
1716  "QC ORD RESIDRMS",
1717  cpl_table_get_column_stdev(table,"Residual"),
1718  "rms resid in ord def",
1719  "%8.4f");
1720 
1721  uves_qclog_add_int(qclog,
1722  "QC ORD NPRED",
1723  pord,
1724  "predicted number of orders",
1725  "%d");
1726 
1727  uves_qclog_add_int(qclog,
1728  "QC ORD NDET",
1729  dord,
1730  "detected number of orders",
1731  "%d");
1732 
1733  uves_qclog_add_int(qclog,
1734  "QC ORD NPOSALL",
1735  dord * samples_per_order,
1736  "Number of position found",
1737  "%d");
1738 
1739  uves_qclog_add_int(qclog,
1740  "QC ORD NPOSSEL",
1741  cpl_table_get_nrow(table),
1742  "Number of position selected",
1743  "%d");
1744 
1745  uves_qclog_add_int(qclog,
1746  "QC ORDMIN",
1747  cpl_table_get_column_min(table,"Order"),
1748  "Number of position selected",
1749  "%d");
1750 
1751  uves_qclog_add_int(qclog,
1752  "QC ORDMAX",
1753  cpl_table_get_column_max(table,"Order"),
1754  "Number of position selected",
1755  "%d");
1756 
1757 
1758 
1759  /* In later MIDAS versions, these were added: */
1760 
1762  uves_remove_string_prefix(UVES_READ_SPEED,"ESO "),
1763  uves_pfits_get_readspeed(raw_header),
1764  "Readout speed",
1765  "%s"));
1766 
1768  uves_remove_string_prefix(UVES_BINX, "ESO "),
1769  uves_pfits_get_binx(raw_header),
1770  "Binning factor along X",
1771  "%d"));
1772 
1774  uves_remove_string_prefix(UVES_BINY, "ESO "),
1775  uves_pfits_get_biny(raw_header),
1776  "Binning factor along Y",
1777  "%d"));
1778 
1780  uves_remove_string_prefix(UVES_INSPATH,"ESO "),
1781  uves_pfits_get_inspath(raw_header),
1782  "Optical path used (h).",
1783  "%s"));
1784 
1785  cleanup:
1786  return;
1787 
1788 }