UVES Pipeline Reference Manual  5.4.6
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  char extname[80];
1159  uves_propertylist* table_header = NULL;
1160 
1161 
1162  /* Read recipe parameters */
1163  {
1164  /* General */
1165  check( uves_get_parameter(parameters, NULL, "uves", "debug", CPL_TYPE_BOOL, &debug_mode),
1166  "Could not read parameter");
1167  check( uves_get_parameter(parameters, NULL, "uves", "process_chip", CPL_TYPE_STRING, &PROCESS_CHIP),
1168  "Could not read parameter");
1169  uves_string_toupper((char*)PROCESS_CHIP);
1170 
1171  /* Preprocessing */
1172  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.use_guess_tab",
1173  CPL_TYPE_INT , &USE_GUESS_TAB), "Could not read parameter");
1174  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.radx",
1175  CPL_TYPE_INT , &RADX), "Could not read parameter");
1176  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.rady",
1177  CPL_TYPE_INT , &RADY), "Could not read parameter");
1178 
1179  check( BM_METHOD = uves_get_bm_method(parameters, recipe_id, "preproc"),
1180  "Could not read background measuring method");
1181 
1182  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.backsubgrid",
1183  CPL_TYPE_INT , &BACKSUBGRID),
1184  "Could not read parameter");
1185  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.backsubradiusy",
1186  CPL_TYPE_INT, &BACKSUBRADIUSY), "Could not read parameter");
1187  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.backsubkappa",
1188  CPL_TYPE_DOUBLE,&BACKSUBKAPPA), "Could not read parameter");
1189  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.backsubdegx",
1190  CPL_TYPE_INT , &BACKSUBDEGX), "Could not read parameter");
1191  check( uves_get_parameter(parameters, NULL, recipe_id, "preproc.backsubdegy",
1192  CPL_TYPE_INT , &BACKSUBDEGY), "Could not read parameter");
1193  /* Hough */
1194  check( uves_get_parameter(parameters, NULL, recipe_id, "hough.samplewidth" ,
1195  CPL_TYPE_INT , &SAMPLEWIDTH), "Could not read parameter");
1196  check( uves_get_parameter(parameters, NULL, recipe_id, "hough.minslope" ,
1197  CPL_TYPE_DOUBLE, &MINSLOPE ), "Could not read parameter");
1198  check( uves_get_parameter(parameters, NULL, recipe_id, "hough.maxslope" ,
1199  CPL_TYPE_DOUBLE, &MAXSLOPE ), "Could not read parameter");
1200  check( uves_get_parameter(parameters, NULL, recipe_id, "hough.sloperes" ,
1201  CPL_TYPE_INT , &SLOPERES ), "Could not read parameter");
1202 /* hough.norders parameter has been temporally removed
1203  check( uves_get_parameter(parameters, NULL, recipe_id, "hough.norders" ,
1204  CPL_TYPE_INT , &NORDERS ), "Could not read parameter");
1205 */
1206  check( uves_get_parameter(parameters, NULL, recipe_id, "hough.pthres" ,
1207  CPL_TYPE_DOUBLE, &PTHRES ), "Could not read parameter");
1208  /* Tracing */
1209  check( uves_get_parameter(parameters, NULL, recipe_id, "trace.tracestep" ,
1210  CPL_TYPE_INT , &TRACESTEP ), "Could not read parameter");
1211  check( uves_get_parameter(parameters, NULL, recipe_id, "trace.minthresh" ,
1212  CPL_TYPE_DOUBLE, &MINTHRESH ), "Could not read parameter");
1213  check( uves_get_parameter(parameters, NULL, recipe_id, "trace.maxgap" ,
1214  CPL_TYPE_DOUBLE, &MAXGAP ), "Could not read parameter");
1215  /* Reject */
1216  check( uves_get_parameter(parameters, NULL, recipe_id, "reject.maxrms" ,
1217  CPL_TYPE_DOUBLE, &MAXRMS ), "Could not read parameter");
1218  check( uves_get_parameter(parameters, NULL, recipe_id, "reject.defpol1" ,
1219  CPL_TYPE_INT , &DEFPOL1_par ), "Could not read parameter");
1220  check( uves_get_parameter(parameters, NULL, recipe_id, "reject.defpol2" ,
1221  CPL_TYPE_INT , &DEFPOL2_par), "Could not read parameter");
1222  check( uves_get_parameter(parameters, NULL, recipe_id, "reject.kappa" ,
1223  CPL_TYPE_DOUBLE, &KAPPA ), "Could not read parameter");
1224 
1225  /* The range of parameters have already been checked by the caller */
1226  /* Do some additional checking */
1227  assure( MINSLOPE < MAXSLOPE , CPL_ERROR_ILLEGAL_INPUT,
1228  "Minimum slope must be smaller than maximum slope (min = %f; max = %f)",
1229  MINSLOPE, MAXSLOPE);
1230  if (MAXSLOPE > 0.5){
1231  uves_msg_warning("Hough transformation might fail when searching for "
1232  "lines with slope larger than 0.5 (maxslope = %f)", MAXSLOPE);
1233  }
1234 
1235  if (DEFPOL1_par >= 6 || DEFPOL2_par >= 6)
1236  {
1237  uves_msg_warning("Polynomial fitting might be unstable with "
1238  "polynomial degrees higher than 5");
1239  }
1240 
1241  }
1242 
1243  /* Load raw image and header, and identify input frame as red or blue */
1244  check( uves_load_orderpos(frames,
1245  flames,
1246  &raw_filename, raw_image,
1247  raw_header, rotated_header, &blue), "Error loading raw frame");
1248 
1249  /* Normalize the range of slopes to match the binning of the input image */
1250  check (binx = uves_pfits_get_binx(raw_header[0]),
1251  "Could not read x binning factor from input header");
1252  check (biny = uves_pfits_get_biny(raw_header[0]),
1253  "Could not read y binning factor from input header");
1254  /* If, for instance, BINX = 2, the slope of a line in the input frame is
1255  twice the slope of the line on the (unbinned) chip, and generally we need
1256  to change SLOPE := BINX/BINY * SLOPE, when going from unbinned to binned
1257  data.
1258  Additionally, when rotating a UVES frame into standard orientation, x- and y-
1259  directions are swapped, so the parameters MINSLOPE and MAXSLOPE must be
1260  multiplied by BINY/BINX to correct for binning. */
1261  MINSLOPE = (MINSLOPE*biny)/binx;
1262  MAXSLOPE = (MAXSLOPE*biny)/binx;
1263 
1264  ord_predict = NORDERS;
1265 
1266  /* Loop over one or two chips */
1267  for (chip = uves_chip_get_first(blue);
1268  chip != UVES_CHIP_INVALID;
1269  chip = uves_chip_get_next(chip))
1270  {
1271 
1272  if(strcmp(PROCESS_CHIP,"REDU") == 0) {
1273  chip = uves_chip_get_next(chip);
1274  }
1275 
1276  table_header = uves_propertylist_new();
1277 
1278  raw_index = uves_chip_get_index(chip);
1279  norders = 0; /* Number of orders detected */
1280 
1281  DEFPOL1 = DEFPOL1_par;
1282  DEFPOL2 = DEFPOL2_par;
1283 
1284  uves_msg("Processing %s chip in '%s'",
1285  uves_chip_tostring_upper(chip), raw_filename);
1286 
1287  check_nomsg( chip_name = uves_pfits_get_chipid(raw_header[raw_index], chip));
1288 
1289  uves_msg_debug("Binning = %dx%d", binx, biny);
1290 
1291  /* If user didn't specify number of orders, then
1292  * Load the DRS-table (MIDAS), or if not present,
1293  * load the guess order table, or if not present,
1294  * auto-detect number of orders
1295  */
1296  if (NORDERS == 0)
1297  {
1298  /* The number of orders to detect will
1299  be read from input guess table (if available),
1300  and it is just a guess: */
1301  norders_is_guess = true;
1302 
1303  uves_free_propertylist(&guess_header);
1304 
1305  if (cpl_frameset_find(frames, UVES_DRS_SETUP(flames, chip)) != NULL)
1306  {
1307  uves_msg_low("No guess order table found");
1308 
1309  check( uves_load_drs(frames, flames, chip_name, &guess_filename,
1310  &guess_header, chip),
1311  "Error loading setup table");
1312 
1313  uves_msg("Using setup table in '%s'", guess_filename);
1314 
1315  check( ord_predict = uves_pfits_get_ordpred(guess_header),
1316  "Could not read predicted number "
1317  "of orders from DRS table header");
1318  }
1319  else if (cpl_frameset_find(frames,
1320  UVES_ORDER_TABLE(flames, chip)) != NULL ||
1321  cpl_frameset_find(frames,
1322  UVES_GUESS_ORDER_TABLE(flames, chip)) != NULL)
1323  {
1324  load_guess = (
1325  cpl_frameset_find(frames,
1326  UVES_GUESS_ORDER_TABLE(flames, chip))
1327  != NULL);
1328 
1329  uves_free_table(&guess_table);
1330 
1331  check( uves_load_ordertable(
1332  frames,
1333  flames,
1334  chip_name,
1335  &guess_filename,
1336  &guess_table,
1337  &guess_header,
1338  NULL,
1339  NULL, /* Don't read order polynomial */
1340  NULL, /* Don't read fibre traces */
1341  NULL, NULL, /* oshift, yshift */
1342  NULL, NULL, /* fibre_pos,fibre_mask */
1343  chip,
1344  load_guess),
1345  "Error loading guess order table");
1346 
1347  uves_msg("Using guess order table in '%s'", guess_filename);
1348 
1349  check( ord_predict = uves_pfits_get_ordpred(guess_header),
1350  "Could not read predicted number of orders from "
1351  "guess order table header");
1352  }
1353  else
1354  {
1355  uves_msg("No guess table found");
1356  }
1357  }
1358  else
1359  {
1360  /* The user has specified the number of orders to detect.
1361  * The user is always right, so don't allow the
1362  * detection algorithm to detect fewer orders.
1363  */
1364  norders_is_guess = false;
1365  }
1366 
1367  /* Load master bias, set pointer to NULL if not present */
1368  uves_free_image(&master_bias);
1369  uves_free_propertylist(&master_bias_header);
1370  if (cpl_frameset_find(frames, UVES_MASTER_BIAS(chip)) != NULL)
1371  {
1372  uves_free_image(&master_bias);
1373  uves_free_propertylist(&master_bias_header);
1374  check( uves_load_mbias(frames,
1375  chip_name,
1376  &master_bias_filename, &master_bias,
1377  &master_bias_header, chip),
1378  "Error loading master bias");
1379 
1380  uves_msg_low("Using master bias in '%s'", master_bias_filename);
1381  cpl_image_subtract(raw_image[raw_index],master_bias);
1382 
1383  }
1384  else
1385  {
1386  uves_msg_low("No master bias in SOF. Bias subtraction not done");
1387  }
1388 
1389  /* Execute macro steps */
1390  check((uves_free_table (&tracetable),
1391  uves_polynomial_delete(&bivariate_fit),
1392  tracetable = uves_orderpos_process_chip(
1393  raw_image[raw_index],
1394  raw_header[raw_index],
1395  rotated_header[raw_index],
1396  chip, binx, biny,
1397  debug_mode,
1398  USE_GUESS_TAB,
1399  RADX, RADY,
1400  BM_METHOD,
1401  BACKSUBGRID,
1402  BACKSUBRADIUSY,
1403  BACKSUBKAPPA,
1404  BACKSUBDEGX, BACKSUBDEGY,
1405  SAMPLEWIDTH,
1406  MINSLOPE, MAXSLOPE,
1407  SLOPERES,
1408  ord_predict,
1409  norders_is_guess,
1410  PTHRES,
1411  TRACESTEP,
1412  MINTHRESH,
1413  MAXGAP,
1414  MAXRMS,
1415  &DEFPOL1,
1416  &DEFPOL2,
1417  KAPPA,
1418  &bivariate_fit,
1419  &norders,
1420  guess_table)),
1421  "Error processing chip");
1422 
1423  /* Finished. Save the products */
1424  uves_msg("Saving products...");
1425 
1426  /* QC parameters should go here.
1427  Other mandatory keywords (FITS + dfs) are
1428  automatically added. */
1429  uves_free_propertylist(&product_header);
1430  product_header = uves_propertylist_new();
1431 
1432  /* Write number of detected orders */
1433  check( uves_pfits_set_ordpred( product_header, norders),
1434  "Error writing number of detected orders");
1435 
1436  if (flames)
1437  {
1438 
1439  check( plate_no = uves_flames_pfits_get_plateid(raw_header[raw_index]),
1440  "Error reading plate id");
1441 
1442  uves_flames_pfits_set_newplateid(product_header, plate_no);
1443  }
1444 
1445  /* Save order trace table */
1446  {
1447  samples_per_order =
1448  cpl_image_get_size_x(raw_image[raw_index]) / TRACESTEP;
1449 
1450  uves_qclog_delete(&qclog[0]);
1451  qclog[0] = uves_qclog_init(raw_header[raw_index], chip);
1452  check_nomsg( uves_orderpos_qclog(tracetable,
1453  flames,
1454  ord_predict,
1455  norders,
1456  samples_per_order,
1457  raw_header[raw_index],chip,qclog[0]));
1458  }
1459 
1460  if (flames) {
1461  /* Write polynomial in MIDAS format, as expected
1462  by flames_cal_prep_sff_ofpos */
1463 
1464  /* Only COEFFI(6) and COEFFI(7) are used */
1465  snprintf(values, 80, "-1 -1 -1 -1 -1 %d %d", DEFPOL1, DEFPOL2);
1466 
1467  uves_propertylist_append_string(product_header,
1468  "HISTORY", "'COEFFI','I*4'");
1469  uves_propertylist_append_string(product_header,
1470  "HISTORY", values);
1471  uves_propertylist_append_string(product_header,
1472  "HISTORY", " ");
1473 
1474  /* Polynomial coeffients */
1475  uves_propertylist_append_string(product_header,
1476  "HISTORY", "'COEFFD','R*8'");
1477  {
1478 
1479  for (j = 0; j <= DEFPOL2; j++) {
1480  for (i = 0; i <= DEFPOL1; i++) {
1481  snprintf(values, 80, "%g",
1482  uves_polynomial_get_coeff_2d(bivariate_fit, i, j));
1483  uves_propertylist_append_string(product_header,
1484  "HISTORY", values);
1485  }
1486  }
1487  }
1488  uves_propertylist_append_string(product_header,
1489  "HISTORY", " ");
1490 
1491  /* Min - max values */
1492  uves_propertylist_append_string(product_header,
1493  "HISTORY", "'COEFFR','R*4'");
1494  snprintf(values, 80, "%g %g",
1495  cpl_table_get_column_min(tracetable, "X"),
1496  cpl_table_get_column_max(tracetable, "X"));
1497  uves_propertylist_append_string(product_header,
1498  "HISTORY", values);
1499 
1500  snprintf(values, 80, "%g %g",
1501  cpl_table_get_column_min(tracetable, "Order"),
1502  cpl_table_get_column_max(tracetable, "Order"));
1503  uves_propertylist_append_string(product_header,
1504  "HISTORY", values);
1505 
1506  uves_propertylist_append_string(product_header,
1507  "HISTORY", " ");
1508  }
1509  uves_pfits_set_extname(product_header,"Order table");
1510  uves_pfits_set_extname(product_header,"Guess order table");
1511  sprintf(extname,"ORDER_TAB");
1512  uves_pfits_set_extname(table_header,extname);
1513  check(( cpl_free(product_filename),
1514  product_filename = uves_order_table_filename(chip),
1515  uves_frameset_insert(frames,
1516  tracetable,
1517  CPL_FRAME_GROUP_PRODUCT,
1518  CPL_FRAME_TYPE_TABLE,
1519  CPL_FRAME_LEVEL_INTERMEDIATE,
1520  product_filename,
1521  UVES_ORD_TAB(flames, chip),
1522  raw_header[raw_index],
1523  product_header,
1524  table_header,
1525  parameters,
1526  recipe_id,
1527  PACKAGE "/" PACKAGE_VERSION,
1528  qclog,
1529  starttime, true, 0)),
1530  "Could not add trace table %s to frameset", product_filename);
1531  uves_qclog_delete(&qclog[0]);
1532  uves_msg("Trace table %s added to frameset", product_filename);
1533  sprintf(extname,"ORDER_POL");
1534  uves_pfits_set_extname(table_header,extname);
1535 
1536  /* Save polynomial in next extension (don't add header keywords) */
1537  check( uves_save_polynomial(bivariate_fit, product_filename, table_header),
1538  "Could not write polynomial to file %s", product_filename);
1539 
1540  /* Original comment:
1541  For compatibility with FLAMES/UVES, create the extension defining
1542  that there is only one trace which has zero offset, and that
1543  this trace is enabled.
1544 
1545  Update after the implementation of FLAMES support:
1546  This extension is not used by FLAMES and is therefore redundant.
1547  But for simplicity, keep it as it was
1548  */
1549  {
1550 
1551  uves_free_table(&traces);
1552  traces = uves_ordertable_traces_new();
1553  uves_ordertable_traces_add(traces, 0, 0.0, 1);
1554  sprintf(extname,"ORDER_INFO");
1555  uves_pfits_set_extname(table_header,extname);
1556 
1557  check( cpl_table_save(traces,
1558  NULL, /* Primary header,
1559  ignored when mode is IO_EXTEND */
1560  table_header, /* Extension header */
1561  product_filename,/* This file already exists
1562  (or an error occurs) */
1563  CPL_IO_EXTEND), /* Append to existing file */
1564  "Error appending table to file '%s'", product_filename);
1565  }
1566  /* Finished saving order table */
1567 
1568  if (flames) {
1569  /* Make two calibration frames out of the input frame */
1570 
1571  /* Save as integer */
1572  uves_free_image(&raw_image_int);
1573  raw_image_int = cpl_image_cast(raw_image[raw_index],
1574  CPL_TYPE_INT);
1575 
1576  check(( cpl_free(product_filename),
1577  product_filename = uves_ordef_filename(chip),
1578  uves_frameset_insert(frames,
1579  raw_image_int,
1580  CPL_FRAME_GROUP_PRODUCT,
1581  CPL_FRAME_TYPE_IMAGE,
1582  CPL_FRAME_LEVEL_INTERMEDIATE,
1583  product_filename,
1584  FLAMES_ORDEF(flames, chip),
1585  raw_header[raw_index], /* raw header */
1586  rotated_header[raw_index], /* output header */
1587  NULL,
1588  parameters,
1589  recipe_id,
1590  PACKAGE "/" PACKAGE_VERSION,
1591  NULL, /* No QC */
1592  starttime, false,
1593  CPL_STATS_MIN | CPL_STATS_MAX)),
1594  "Could not add raw frame %s to frameset", product_filename);
1595 
1596  uves_msg("Raw frame %s added to frameset", product_filename);
1597  uves_free_image(&raw_image_int);
1598  }
1599 
1600  if(strcmp(PROCESS_CHIP,"REDL") == 0) {
1601  chip = uves_chip_get_next(chip);
1602  }
1603 
1604  uves_free_propertylist(&table_header);
1605  } /* For each chip */
1606 
1607  cleanup:
1608  /* Raw */
1609  uves_free_image(&(raw_image[0]));
1610  uves_free_image(&(raw_image[1]));
1611  uves_free_image(&raw_image_int);
1612  uves_free_propertylist(&(raw_header[0]));
1613  uves_free_propertylist(&(raw_header[1]));
1614  uves_free_propertylist(&(rotated_header[0]));
1615  uves_free_propertylist(&(rotated_header[1]));
1616 
1617  /* Master bias */
1618  uves_free_image(&master_bias);
1619  uves_free_propertylist(&master_bias_header);
1620 
1621  /* Calibration */
1622  uves_free_propertylist(&guess_header);
1623  uves_free_table (&guess_table);
1624 
1625  /* Product */
1626  uves_qclog_delete(&qclog[0]);
1627  uves_free_table (&tracetable);
1628  uves_polynomial_delete(&bivariate_fit);
1629  uves_free_table (&traces);
1630  uves_free_propertylist(&product_header);
1631  cpl_free(product_filename);
1632 
1633  return;
1634 }
1645 static void uves_orderpos_qclog(cpl_table* table,
1646  bool flames,
1647  int pord,
1648  int dord,
1649  int samples_per_order,
1650  uves_propertylist* raw_header,
1651  enum uves_chip chip,
1652  cpl_table* qclog)
1653 {
1654  const char* chip_name;
1655  const char* grat_name;
1656  const char* ins_mode;
1657  double grat_wlen=0;
1658 
1659  uves_qclog_add_string(qclog,
1660  "QC TEST1 ID",
1661  flames ?
1662  "Single-Fibre-Order-Definition-Results" :
1663  "Order-Definition-Results",
1664  "Name of QC test",
1665  "%s");
1666 
1667  check_nomsg( chip_name=uves_pfits_get_chip_name(raw_header,chip) );
1668  /* chip_name = UVES_QC_CHIP_VAL(chip); */
1669 
1670  uves_qclog_add_string(qclog,
1671  uves_remove_string_prefix(UVES_CHIP_NAME(chip),"ESO "),
1672  chip_name,
1673  "Grating unique ID",
1674  "%s");
1675 
1676 
1677  check_nomsg(grat_name=uves_pfits_get_gratname(raw_header,chip));
1678 
1679 
1680 
1681  uves_qclog_add_string(qclog,
1682  uves_remove_string_prefix(UVES_GRATNAME(chip),"ESO "),
1683  grat_name,
1684  "Cross disperser ID",
1685  "%s");
1686 
1687 
1688  check_nomsg(ins_mode=uves_pfits_get_insmode(raw_header));
1689  uves_qclog_add_string(qclog,
1690  uves_remove_string_prefix(UVES_INSMODE,"ESO "),
1691  ins_mode,
1692  "Instrument mode used.",
1693  "%s");
1694 
1695 
1696  check_nomsg(grat_wlen=uves_pfits_get_gratwlen(raw_header,chip));
1697  uves_qclog_add_double(qclog,
1698  uves_remove_string_prefix(UVES_GRATWLEN(chip),"ESO "),
1699  grat_wlen,
1700  "Grating central wavelength [nm]",
1701  "%.1f");
1702 
1703  uves_msg_debug("chip_name=%s grat_name=%s ins_mode=%s grat_wlen=%f",
1704  chip_name,grat_name,ins_mode,grat_wlen);
1705 
1706  uves_qclog_add_double(qclog,
1707  "QC ORD RESIDMIN",
1708  cpl_table_get_column_min(table,"Residual"),
1709  "min resid in ord def",
1710  "%8.4f");
1711 
1712  uves_qclog_add_double(qclog,
1713  "QC ORD RESIDMAX",
1714  cpl_table_get_column_max(table,"Residual"),
1715  "max resid in ord def",
1716  "%8.4f");
1717 
1718  uves_qclog_add_double(qclog,
1719  "QC ORD RESIDAVG",
1720  cpl_table_get_column_mean(table,"Residual"),
1721  "mean resid in ord def",
1722  "%8.4f");
1723 
1724  uves_qclog_add_double(qclog,
1725  "QC ORD RESIDRMS",
1726  cpl_table_get_column_stdev(table,"Residual"),
1727  "rms resid in ord def",
1728  "%8.4f");
1729 
1730  uves_qclog_add_int(qclog,
1731  "QC ORD NPRED",
1732  pord,
1733  "predicted number of orders",
1734  "%d");
1735 
1736  uves_qclog_add_int(qclog,
1737  "QC ORD NDET",
1738  dord,
1739  "detected number of orders",
1740  "%d");
1741 
1742  uves_qclog_add_int(qclog,
1743  "QC ORD NPOSALL",
1744  dord * samples_per_order,
1745  "Number of position found",
1746  "%d");
1747 
1748  uves_qclog_add_int(qclog,
1749  "QC ORD NPOSSEL",
1750  cpl_table_get_nrow(table),
1751  "Number of position selected",
1752  "%d");
1753 
1754  uves_qclog_add_int(qclog,
1755  "QC ORDMIN",
1756  cpl_table_get_column_min(table,"Order"),
1757  "Number of position selected",
1758  "%d");
1759 
1760  uves_qclog_add_int(qclog,
1761  "QC ORDMAX",
1762  cpl_table_get_column_max(table,"Order"),
1763  "Number of position selected",
1764  "%d");
1765 
1766 
1767 
1768  /* In later MIDAS versions, these were added: */
1769 
1771  uves_remove_string_prefix(UVES_READ_SPEED,"ESO "),
1772  uves_pfits_get_readspeed(raw_header),
1773  "Readout speed",
1774  "%s"));
1775 
1777  uves_remove_string_prefix(UVES_BINX, "ESO "),
1778  uves_pfits_get_binx(raw_header),
1779  "Binning factor along X",
1780  "%d"));
1781 
1783  uves_remove_string_prefix(UVES_BINY, "ESO "),
1784  uves_pfits_get_biny(raw_header),
1785  "Binning factor along Y",
1786  "%d"));
1787 
1789  uves_remove_string_prefix(UVES_INSPATH,"ESO "),
1790  uves_pfits_get_inspath(raw_header),
1791  "Optical path used (h).",
1792  "%s"));
1793 
1794  cleanup:
1795  return;
1796 
1797 }
cpl_error_code uves_filter_image_median(cpl_image **image, int xwindow, int ywindow, bool extrapolate_border)
Median filter.
void uves_polynomial_delete(polynomial **p)
Delete a polynomial.
#define uves_msg_warning(...)
Print an warning message.
Definition: uves_msg.h:87
int uves_flames_pfits_get_plateid(const uves_propertylist *raw_header)
read the plate id
Definition: uves_pfits.c:3201
int uves_qclog_add_string(cpl_table *table, const char *key_name, const char *value, const char *key_help, const char *format)
Add string key to QC-LOG table.
Definition: uves_qclog.c:683
cpl_image * uves_define_noise(const cpl_image *image, const uves_propertylist *image_header, int ncom, enum uves_chip chip)
Create noise image.
Definition: uves_utils.c:2226
#define check_nomsg(CMD)
Definition: uves_error.h:204
cpl_table * uves_ordertable_traces_new(void)
Create the table that describes fibre traces.
Definition: uves_utils.c:3898
int uves_pfits_get_ordpred(const uves_propertylist *plist)
Read the predicted number of orders.
Definition: uves_pfits.c:1522
cpl_table * uves_hough(const cpl_image *image, int ymin, int ymax, int NORDERS, bool norders_is_guess, int SAMPLEWIDTH, double PTHRES, double MINSLOPE, double MAXSLOPE, int SLOPERES, bool consecutive, cpl_image **htrans, cpl_image **htrans_original)
Compute Hough transform and detect lines.
int uves_qclog_delete(cpl_table **table)
delete QC-LOG table
Definition: uves_qclog.c:716
double uves_pfits_get_gratwlen(const uves_propertylist *plist, enum uves_chip chip)
find out the central wavelength
Definition: uves_pfits.c:1371
int uves_qclog_add_double(cpl_table *table, const char *key_name, const double value, const char *key_help, const char *format)
Add double key to QC-LOG table.
Definition: uves_qclog.c:641
cpl_table * uves_locate_orders(const cpl_image *inputimage, const cpl_image *noise, cpl_table *ordertable, int TRACESTEP, double MINTHRESH, double MAXGAP, double MAXRMS, int *DEFPOL1, int *DEFPOL2, double KAPPA, polynomial **bivariate_fit, int *orders_traced)
Trace all orders.
void uves_flames_pfits_set_newplateid(uves_propertylist *plist, int plate_no)
Write the plate number.
Definition: uves_pfits.c:3273
double uves_polynomial_get_coeff_2d(const polynomial *p, int degree1, int degree2)
Get a coefficient of a 2D polynomial.
const char * uves_pfits_get_chip_name(const uves_propertylist *plist, enum uves_chip chip)
Find out the chip name.
Definition: uves_pfits.c:639
int uves_qclog_add_int(cpl_table *table, const char *key_name, const int value, const char *key_help, const char *format)
Add integer key to QC-LOG table.
Definition: uves_qclog.c:521
double uves_polynomial_derivative_2d(const polynomial *p, double x1, double x2, int varno)
Evaluate the partial derivative of a 2d polynomial.
uves_propertylist * uves_propertylist_new(void)
Create an empty property list.
int uves_pfits_get_binx(const uves_propertylist *plist)
Find out the x binning factor.
Definition: uves_pfits.c:1176
#define uves_msg(...)
Print a message on 'info' or 'debug' level.
Definition: uves_msg.h:119
int uves_pfits_get_biny(const uves_propertylist *plist)
Find out the y binning factor.
Definition: uves_pfits.c:1194
cpl_error_code uves_propertylist_copy_property_regexp(uves_propertylist *self, const uves_propertylist *other, const char *regexp, int invert)
Copy matching properties from another property list.
polynomial * uves_polynomial_regression_2d_autodegree(cpl_table *t, const char *X1, const char *X2, const char *Y, const char *sigmaY, const char *polynomial_fit, const char *residual_square, const char *variance_fit, double *mean_squared_error, double *red_chisq, polynomial **variance, double kappa, int maxdeg1, int maxdeg2, double min_rms, double min_reject, bool verbose, const double *min_val, const double *max_val, int npos, double positions[][2])
Fit a 2d polynomial to three table columns.
Definition: uves_utils.c:3305
bool uves_ccd_is_new(const uves_propertylist *plist)
Find out if CCD header is new.
Definition: uves_pfits.c:553
const char * uves_remove_string_prefix(const char *s, const char *prefix)
Remove named prefix from string.
Definition: uves_utils.c:3612
const char * uves_pfits_get_gratname(const uves_propertylist *plist, enum uves_chip chip)
find out the grating name value
Definition: uves_pfits.c:1427
double uves_polynomial_evaluate_2d(const polynomial *p, double x1, double x2)
Evaluate a 2d polynomial.
int uves_physmod_chop_otab(const uves_propertylist *raw_header, enum uves_chip chip, cpl_table **ord_tbl, const char *col_name, int *ord_min, int *ord_max)
Chop off orders which are not fully in the detector chip.
const char * uves_pfits_get_insmode(const uves_propertylist *plist)
find out the chip name value
Definition: uves_pfits.c:1391
const char * uves_pfits_get_inspath(const uves_propertylist *plist)
find out the chip name value
Definition: uves_pfits.c:1409
int uves_chip_get_index(enum uves_chip chip)
Convert to integer.
Definition: uves_chip.c:124
enum uves_chip uves_chip_get_first(bool blue)
Get first chip for blue or red arm.
Definition: uves_chip.c:92
const char * uves_pfits_get_readspeed(const uves_propertylist *plist)
find out the readout speed
Definition: uves_pfits.c:1446
cpl_error_code uves_ordertable_traces_add(cpl_table *traces, int fibre_ID, double fibre_offset, int fibre_mask)
Add a trace.
Definition: uves_utils.c:3925
cpl_error_code uves_pfits_set_extname(uves_propertylist *plist, const char *extname)
Write the EXTNAME keyword.
Definition: uves_pfits.c:2736
#define uves_msg_low(...)
Print a message on a lower message level.
Definition: uves_msg.h:105
enum uves_chip uves_chip_get_next(enum uves_chip chip)
Get next chip.
Definition: uves_chip.c:108
#define uves_msg_debug(...)
Print a debug message.
Definition: uves_msg.h:97
const char * uves_chip_tostring_upper(enum uves_chip chip)
Convert to string.
Definition: uves_chip.c:156
cpl_error_code uves_draw_orders(const cpl_table *ordertable, cpl_image *image)
Draw detected order lines.
int uves_correct_badpix_all(cpl_image *master_bias, uves_propertylist *mbias_header, enum uves_chip chip, int binx, int biny, int mark_bad, bool red_ccd_new)
Correct all bad pixels on a chip.
const char * uves_string_toupper(char *s)
Convert all lowercase characters in a string into uppercase characters.
Definition: uves_utils.c:1493
cpl_error_code uves_pfits_set_ordpred(uves_propertylist *plist, int nord)
Write the predicted number of order.
Definition: uves_pfits.c:1000
#define check(CMD,...)
Definition: uves_error.h:198
cpl_table * uves_qclog_init(const uves_propertylist *raw_header, enum uves_chip chip)
Init QC-LOG table.
Definition: uves_qclog.c:410
const char * uves_pfits_get_chipid(const uves_propertylist *plist, enum uves_chip chip)
Find out the chip ID.
Definition: uves_pfits.c:619