SINFONI Pipeline Reference Manual  2.6.0
sinfo_utl_illumcorr.c
1 /* $Id: sinfo_utl_illumcorr.c,v 1.18 2012-03-03 10:38:03 amodigli Exp $
2  *
3  * This file is part of the CPL (Common Pipeline Library)
4  * Copyright (C) 2002 European Southern Observatory
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 /*
21  * $Author: amodigli $
22  * $Date: 2012-03-03 10:38:03 $
23  * $Revision: 1.18 $
24  * $Name: not supported by cvs2svn $
25  */
26 
27 /****************************************************************
28  * Object Data reduction *
29  ****************************************************************/
30 
31 #ifdef HAVE_CONFIG_H
32 #include <config.h> /* allows the program compilation */
33 #endif
34 
35 /*-----------------------------------------------------------------------------
36  Includes
37 -----------------------------------------------------------------------------*/
38 
39 /* std */
40 #include <strings.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <math.h>
44 #include <libgen.h>
45 
46 
47 /* cpl */
48 #include <cpl.h>
49 
50 /* irplib */
51 #include <irplib_utils.h>
52 
53 /* sinfoni */
54 #include <sinfo_pro_types.h>
55 #include <sinfo_product_config.h>
56 #include <sinfo_prepare_stacked_frames_config.h>
57 #include <sinfo_objnod_config.h>
58 #include <sinfo_new_objnod.h>
59 #include <sinfo_new_prepare_stacked_frames.h>
60 #include <sinfo_pro_save.h>
61 #include <sinfo_raw_types.h>
62 #include <sinfo_functions.h>
63 #include <sinfo_tpl_utils.h>
64 #include <sinfo_tpl_dfs.h>
65 #include <sinfo_hidden.h>
66 #include <sinfo_globals.h>
67 #include <sinfo_rec_utils.h>
68 
69 
70 /*-----------------------------------------------------------------------------
71  Function prototypes
72 -----------------------------------------------------------------------------*/
73 static int sinfo_utl_illumcorr_create(cpl_plugin *plugin);
74 static int sinfo_utl_illumcorr_exec(cpl_plugin *plugin);
75 static int sinfo_utl_illumcorr_destroy(cpl_plugin *plugin);
76 static int sinfo_utl_illumcorr(cpl_parameterlist *config, cpl_frameset *set);
77 
78 
79 #define SINFO_DOUBLE_SWAP(a,b) { register double t=(a);(a)=(b);(b)=t; }
80 
81 static cpl_error_code
82 sinfo_tools_sort_double(
83  double * pix_arr,
84  int n);
85 
86 static cpl_frame*
87 sinfo_get_dummy_object(cpl_frameset* obj_set);
88 
89 static void
90 sinfo_illumcorr_config_add (cpl_parameterlist *list);
91 
92 static int
93 create_illumcorr (const char* plugin_id,
94  cpl_parameterlist *cpl_cfg,
95  cpl_frameset* sof,
96  const char *name_i);
97 static int
98 sinfo_illumcorr_create_bins (cpl_imagelist *sky,
99  int llx, int lly, int urx, int ury,
100  int spec_bin,
101  double min_flux,
102  int ** start,
103  int ** end,
104  int z1, int z2);
105 
106 static int
107 sinfo_juha_function1d_natural_spline(double *, double *, int, double *,
108  double *, int);
109 
110 static int
111 sinfo_function1d_search_value(double *, int, double, int *) ;
112 
113 static cpl_vector *
114 sinfo_vector_filter_median_create(const cpl_vector * v, int hw);
115 
116 static cpl_vector *
117 sinfo_juha_vector_filter_median_create(const cpl_vector * v, int hw);
118 
119 static double
120 sinfo_image_get_median_window (const cpl_image *image,
121  int llx, int lly, int urx, int ury);
122 
123 
124 /*-----------------------------------------------------------------------------
125  Static variables
126 -----------------------------------------------------------------------------*/
127 
128 static char sinfo_utl_illumcorr_description1[] =
129  "This recipe calculates illumination correction based on sky emission.\n"
130  "The input files are sky (or object) frames tagged\n"
131  " SKY_NODDING (OBJECT_NODDING)\n"
132  "Master calibration frames:\n";
133 
134 
135 static char sinfo_utl_illumcorr_description2[] =
136  "A corresponding (DIT) dark frame (tag=MASTER_DARK)"
137  "A corresponding (band,preoptics) wavelength map image (tag=WAVE_MAP)\n"
138  "A corresponding (band,preoptics) master flat field (tag=MASTER_FLAT_LAMP)\n"
139  "A corresponding (band,preoptics) master bad pixel map (tag=MASTER_BP_MAP)\n"
140  "A corresponding (band,preoptics) slitlets position frame (tag=SLIT_POS)\n"
141  "A corresponding (band) distortion table (tag=DISTORTION)\n"
142  "A corresponding (band) slitlet distance table (tag=SLITLETS_DISTANCE)\n";
143 
144 
145 static char sinfo_utl_illumcorr_description3[] =
146  "The output is a cube resulting from the analysis of sky emission\n"
147  "\n";
148 
149 
150 static char sinfo_utl_illumcorr_description[1300];
151 
152 /*-----------------------------------------------------------------------------
153  Functions code
154 -----------------------------------------------------------------------------*/
155 
157 /*---------------------------------------------------------------------------*/
162 /*---------------------------------------------------------------------------*/
163 static int
164 sinfo_utl_illumcorr_create(cpl_plugin *plugin)
165 {
166 
167  /*
168  * We have to provide the option we accept to the application.
169  * We need to setup our parameter list and hook it into the recipe
170  * interface.
171  */
172  cpl_recipe *recipe = (cpl_recipe *)plugin;
173  recipe->parameters = cpl_parameterlist_new();
174  if(recipe->parameters == NULL) {
175  return 1;
176  }
177  cpl_error_reset();
178  irplib_reset();
179 
180  /*
181  * Fill the parameter list.
182  */
183  sinfo_product_config_add (recipe->parameters);
184  sinfo_prepare_stacked_frames_config_add(recipe->parameters);
185  sinfo_objnod_config_add(recipe->parameters);
186  sinfo_illumcorr_config_add (recipe->parameters);
187 
188  return 0;
189 
190 }
191 
192 /*---------------------------------------------------------------------------*/
198 /*---------------------------------------------------------------------------*/
199 static int
200 sinfo_utl_illumcorr_exec(cpl_plugin *plugin)
201 {
202 
203  cpl_recipe *recipe = (cpl_recipe *) plugin;
204  int code=0;
205  cpl_errorstate initial_errorstate = cpl_errorstate_get();
206 
207  if(recipe->parameters == NULL) {
208  return 1;
209  }
210  if(recipe->frames == NULL) {
211  return 1;
212  }
213  code=sinfo_utl_illumcorr(recipe->parameters, recipe->frames);
214 
215  if (!cpl_errorstate_is_equal(initial_errorstate)) {
216  /* Dump the error history since recipe execution start.
217  At this point the recipe cannot recover from the error */
218  cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);
219  }
220  return code;
221 
222 
223 }
224 
225 /*---------------------------------------------------------------------------*/
231 /*---------------------------------------------------------------------------*/
232 static int
233 sinfo_utl_illumcorr_destroy(cpl_plugin *plugin)
234 {
235  cpl_recipe *recipe = (cpl_recipe *) plugin;
236  /*
237  * We just destroy what was created during the plugin initializzation phase
238  * i.e. the parameter list. The frame set is managed by the application which
239  * called us, so that we must not touch it.
240  */
241 
242  cpl_parameterlist_delete(recipe->parameters);
243 
244  return 0;
245 
246 }
247 
248 /*---------------------------------------------------------------------------*/
256 /*---------------------------------------------------------------------------*/
257 int
258 cpl_plugin_get_info(cpl_pluginlist *list)
259 {
260 
261  cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
262  cpl_plugin *plugin = &recipe->interface;
263 
264  strcpy(sinfo_utl_illumcorr_description,sinfo_utl_illumcorr_description1);
265  strcat(sinfo_utl_illumcorr_description,sinfo_utl_illumcorr_description2);
266  strcat(sinfo_utl_illumcorr_description,sinfo_utl_illumcorr_description3);
267 
268  cpl_plugin_init(plugin,
269  CPL_PLUGIN_API,
270  SINFONI_BINARY_VERSION,
271  CPL_PLUGIN_TYPE_RECIPE,
272  "sinfo_utl_illumcorr",
273  "Object data reduction",
274  sinfo_utl_illumcorr_description,
275  "Juha Reunanen",
276  "reunanen@strw.leidenuniv.nl",
277  sinfo_get_license(),
278  sinfo_utl_illumcorr_create,
279  sinfo_utl_illumcorr_exec,
280  sinfo_utl_illumcorr_destroy);
281 
282  cpl_pluginlist_append(list, plugin);
283 
284  return 0;
285 
286 }
287 
288 /*
289  * The actual recipe actually start here.
290  */
291 
292 static int
293 sinfo_utl_illumcorr(cpl_parameterlist *config, cpl_frameset *set)
294 {
295  char outname[FILE_NAME_SZ];
296 
297  int i=0;
298  int k=0;
299 
300  int ind=0;
301  int nsky=0;
302  int nobj=0;
303  int ncdb=0;
304  int nstk=0;
305 
306  cpl_frameset * obj_set=NULL;
307  cpl_frameset * sky_set=NULL;
308  cpl_frameset * cdb_set=NULL;
309  cpl_frameset * wrk_set=NULL;
310  cpl_frameset * stk_set=NULL;
311  cpl_frame * sky_frm=NULL;
312 
313  cpl_frame * wrk_frm=NULL;
314  cpl_frameset * ref_set=NULL;
315 
316  cpl_frame * dark_frm=NULL;
317 
318  fake* fk;
319 
320 
321  cpl_image * ima1=NULL ;
322  cpl_image * ima2=NULL ;
323  cpl_image * resima=NULL ;
324  cpl_propertylist * plist=NULL ;
325  cpl_frame * product_frame=NULL;
326  const char *name_i=NULL;
327 
328  /* cpl_parameterlist_dump(config); */
329  sinfo_msg("Welcome to SINFONI Pipeline release %d.%d.%d",
330  SINFONI_MAJOR_VERSION,SINFONI_MINOR_VERSION,SINFONI_MICRO_VERSION);
331 
332  if(sinfo_dfs_set_groups(set)) {
333  sinfo_msg_error("Cannot identify RAW and CALIB frames") ;
334  return -1;
335  }
336 
337  dark_frm = cpl_frameset_find(set,PRO_MASTER_DARK);
338  if (dark_frm == NULL) {
339  sinfo_msg_error("Cannot find dark frame") ;
340  return (-1);
341  }
342 
343  ref_set=cpl_frameset_duplicate(set);
344 
345  obj_set=cpl_frameset_new();
346  sky_set=cpl_frameset_new();
347  cdb_set=cpl_frameset_new();
348  fk = sinfo_fake_new();
349 
350  sinfo_extract_obj_frames(set,obj_set);
351  sinfo_extract_sky_frames(set,sky_set);
352  sinfo_extract_mst_frames(set,cdb_set);
353 
354  nobj=cpl_frameset_get_size(obj_set);
355  nsky=cpl_frameset_get_size(sky_set);
356  ncdb=cpl_frameset_get_size(cdb_set);
357 
358  if ((nobj==0) && (nsky==0)) {
359  sinfo_msg_error("Empty input set");
360  cpl_frameset_delete(obj_set);
361  cpl_frameset_delete(sky_set);
362  cpl_frameset_delete(cdb_set);
363  cpl_frameset_delete(ref_set);
364  sinfo_fake_delete(&fk);
365  return (-1);
366  }
367 
368 
369  /*
370  * Create median collapsed sky frame either from real SKY frames,
371  * or from jittered OBJECT frames
372  */
373  if ( nsky != 0) {
374  if( (sky_frm = sinfo_get_dummy_object(sky_set)) == NULL) {
375  sinfo_msg_error("Problem to get dummy frame");
376  cpl_frameset_delete(obj_set);
377  cpl_frameset_delete(sky_set);
378  cpl_frameset_delete(cdb_set);
379  cpl_frameset_delete(ref_set);
380  sinfo_fake_delete(&fk);
381  return (-1);
382  }
383  }
384  else {
385  if( (sky_frm = sinfo_get_dummy_object(obj_set)) == NULL) {
386  sinfo_msg_error("Problem to get dummy frame");
387  cpl_frameset_delete(obj_set);
388  cpl_frameset_delete(sky_set);
389  cpl_frameset_delete(cdb_set);
390  cpl_frameset_delete(ref_set);
391  sinfo_fake_delete(&fk);
392  return (-1);
393  }
394  }
395 
396  /*
397  * Seems it's not possible to use draks as sky (due to INS.GRAT1.ENC)
398  * and stacking phase subtracts dark only in special circumstances...
399  */
400  ima1 = cpl_image_load(cpl_frame_get_filename(sky_frm),CPL_TYPE_FLOAT,0,0);
401  ima2 = cpl_image_load(cpl_frame_get_filename(dark_frm),CPL_TYPE_FLOAT,0,0);
402  resima = cpl_image_subtract_create(ima1, ima2);
403  plist=cpl_propertylist_load(cpl_frame_get_filename(sky_frm), 0);
404  cpl_image_delete(ima1);
405  cpl_image_delete(ima2);
406 
407  product_frame = cpl_frame_new();
408  cpl_frame_set_filename(product_frame, "out_fake_object2.fits") ;
409  cpl_frame_set_tag(product_frame, "OBJECT_NODDING") ;
410  cpl_frame_set_type(product_frame, CPL_FRAME_TYPE_IMAGE) ;
411  cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_RAW) ;
412  //cpl_frame_set_level(product_frame, CPL_FR) ;
413  cpl_propertylist_erase_regexp(plist, "^ESO PRO CATG",0);
414 
415  cpl_image_save(resima, "out_fake_object2.fits", CPL_BPP_IEEE_FLOAT, plist,
416  CPL_IO_DEFAULT) ;
417  cpl_propertylist_delete(plist) ;
418  cpl_image_delete(resima) ;
419 
420 
421  /*
422  * Stack it - with some trickery...
423  */
424  wrk_set=cpl_frameset_new();
425 
426  cpl_frame* dup_frm=cpl_frame_duplicate(product_frame);
427  cpl_frame_set_tag (dup_frm, "OBJECT_NODDING");
428  cpl_frame_set_group (dup_frm ,CPL_FRAME_GROUP_RAW);
429  cpl_frameset_insert(wrk_set,dup_frm);
430 
431  /* merge CDB frames to work set */
432  for(k=0;k<ncdb;k++) {
433  cpl_frame* cdb_frm=cpl_frameset_get_frame(cdb_set,k);
434  dup_frm=cpl_frame_duplicate(cdb_frm);
435  cpl_frameset_insert(wrk_set,dup_frm);
436  }
437 
438 
439  /* defines a new name for the output stacked frame */
440  sprintf(outname,"%s%d%s","out_stack",i,".fits");
441  if(-1 == sinfo_new_stack_frames(config,wrk_set,
442  PRO_OBJECT_NODDING_STACKED,i,fk,cpl_func)) {
443 
444  cpl_frameset_delete(wrk_set);
445  //cpl_frameset_delete(tot_set);
446  cpl_frameset_delete(obj_set);
447  cpl_frameset_delete(sky_set);
448  cpl_frameset_delete(cdb_set);
449  cpl_frameset_delete(ref_set);
450  sinfo_fake_delete(&fk);
451  return -1;
452  }
453 
454  stk_set=cpl_frameset_new();
455  sinfo_contains_frames_kind(wrk_set,stk_set,PRO_STACKED);
456  nstk=cpl_frameset_get_size(stk_set);
457 
458  for(k=0;k<nstk;k++) {
459  wrk_frm=cpl_frameset_get_frame(stk_set,k);
460  dup_frm = cpl_frame_duplicate(wrk_frm);
461  cpl_frameset_insert(set,dup_frm);
462  }
463  cpl_frameset_delete(stk_set);
464  cpl_frameset_delete(wrk_set);
465 
466  sinfo_msg("------------------------------") ;
467  sinfo_msg("CREATING SKY CUBE");
468  sinfo_msg("------------------------------") ;
469 
470 
471  if ( -1 == (ind=sinfo_new_objnod(cpl_func,config, set, PRO_COADD_OBJ ) ) ) {
472  sinfo_msg_error("NODDING SCIENCE FRAMES no. %d\n", ind) ;
473  cpl_frameset_delete(obj_set);
474  cpl_frameset_delete(sky_set);
475  cpl_frameset_delete(cdb_set);
476  cpl_frameset_delete(ref_set);
477  sinfo_fake_delete(&fk);
478 
479  return (-1);
480  }
481  sinfo_msg("------------------------------") ;
482  sinfo_msg("CREATED SKY CUBE");
483  sinfo_msg("------------------------------") ;
484 
485 
486  stk_set=cpl_frameset_new();
487  sinfo_contains_frames_kind(set, stk_set, PRO_OBS_OBJ);
488 
489 
490  wrk_frm=cpl_frameset_get_frame(stk_set,0);
491  name_i = cpl_frame_get_filename(wrk_frm);
492 
493 
494  //cpl_frameset_delete(wrk_set);
495  cpl_frameset_delete(obj_set);
496  cpl_frameset_delete(sky_set);
497  cpl_frameset_delete(cdb_set);
498  cpl_frameset_delete(ref_set);
499  sinfo_fake_delete(&fk);
500  cpl_frame_delete(sky_frm);
501  create_illumcorr (cpl_func, config, set, name_i);
502 
503  return (0);
504 
505 }
506 
507 
508 static cpl_frame*
509 sinfo_get_dummy_object(cpl_frameset* obj_set)
510 {
511 
512  cpl_imagelist* obj_list=NULL;
513  cpl_image* fake_object=NULL;
514  char filename[FILE_NAME_SZ];
515  cpl_frame* frame=NULL;
516  cpl_frame* object_frame=NULL;
517 
518  cpl_propertylist* plist=NULL;
519 
520  obj_list = cpl_imagelist_load_frameset(obj_set,CPL_TYPE_FLOAT,0,0);
521  fake_object = cpl_imagelist_collapse_median_create(obj_list);
522 
523  frame = cpl_frameset_get_frame(obj_set,0);
524  strcpy(filename,cpl_frame_get_filename(frame));
525 
526  if ((cpl_error_code)((plist = cpl_propertylist_load(filename, 0)) == NULL)) {
527  sinfo_msg_error("getting header from reference ima frame %s",filename);
528  cpl_propertylist_delete(plist) ;
529  return NULL ;
530  }
531 
532  if (cpl_propertylist_has(plist, KEY_NAME_DPR_TYPE)) {
533  cpl_propertylist_set_string(plist, KEY_NAME_DPR_TYPE, "OBJECT");
534  } else {
535  cpl_propertylist_append_string(plist, KEY_NAME_DPR_TYPE,"OBJECT") ;
536  }
537 
538  if (cpl_image_save(fake_object, "out_fake_object.fits", CPL_BPP_IEEE_FLOAT,
539  plist,CPL_IO_DEFAULT)!=CPL_ERROR_NONE) {
540  sinfo_msg_error("Cannot save the product %s","out_fake_object.fits");
541  cpl_propertylist_delete(plist) ;
542  return NULL ;
543  }
544  cpl_propertylist_delete(plist);
545 
546  object_frame = cpl_frame_new() ;
547  cpl_frame_set_filename(object_frame, "out_fake_object.fits") ;
548  cpl_frame_set_tag(object_frame, "OBJECT") ;
549  cpl_frame_set_type(object_frame, CPL_FRAME_TYPE_IMAGE);
550  /*
551  cpl_frame_set_group(object_frame, CPL_FRAME_GROUP_PRODUCT);
552  */
553  cpl_frame_set_level(object_frame, CPL_FRAME_LEVEL_FINAL);
554  cpl_image_delete(fake_object);
555  cpl_imagelist_delete(obj_list);
556 
557  return object_frame;
558 }
559 
560 static void
561 sinfo_illumcorr_config_add (cpl_parameterlist *list)
562 {
563  cpl_parameter *p;
564 
565  if (!list) {
566  return;
567  }
568 
569  p = cpl_parameter_new_range("sinfoni.illumcorr.spec_bin",
570  CPL_TYPE_INT,
571  "Number of spectral planes to be combined ",
572  "sinfoni.illumcorr",
573  100, 1, 200);
574  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-spec_bin");
575  cpl_parameterlist_append(list, p);
576 
577  p = cpl_parameter_new_value("sinfoni.illumcorr.min_flux",
578  CPL_TYPE_DOUBLE,
579  "Minimum flux in each spectral bin ",
580  "sinfoni.illumcorr",
581  0.0);
582  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-min_flux");
583  cpl_parameterlist_append(list, p);
584 
585  p = cpl_parameter_new_value("sinfoni.illumcorr.center_bins",
586  CPL_TYPE_BOOL,
587  "Center the spectral bins at prominent "
588  "emission features ",
589  "sinfoni.illumcorr",
590  FALSE);
591  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-center_bins");
592  cpl_parameterlist_append(list, p);
593 
594  p = cpl_parameter_new_enum("sinfoni.illumcorr.order",
595  CPL_TYPE_INT,
596  "The order of the polynomial to be fitted "
597  "for each slitlet",
598  "sinfoni.illumcorr",
599  0,
600  2,0,1);
601  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-order");
602  cpl_parameterlist_append(list, p);
603 
604  p = cpl_parameter_new_value("sinfoni.illumcorr.sigma",
605  CPL_TYPE_DOUBLE,
606  "Reject n-sigma deviant pixels on each slitlet ",
607  "sinfoni.illumcorr",
608  3.0);
609  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-sigma");
610  cpl_parameterlist_append(list, p);
611 
612  p = cpl_parameter_new_value("sinfoni.illumcorr.iterations",
613  CPL_TYPE_INT,
614  "Number of sigma rejection iterations to run ",
615  "sinfoni.illumcorr",
616  3);
617  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-iter");
618  cpl_parameterlist_append(list, p);
619 
620  p = cpl_parameter_new_range("sinfoni.illumcorr.llx",
621  CPL_TYPE_INT,
622  "Reference region coordinates ",
623  "sinfoni.illumcorr",
624  8, 0, 63);
625  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-llx");
626  cpl_parameterlist_append(list, p);
627 
628  p = cpl_parameter_new_range("sinfoni.illumcorr.lly",
629  CPL_TYPE_INT,
630  "Reference region coordinates ",
631  "sinfoni.illumcorr",
632  33, 0, 63);
633  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-lly");
634  cpl_parameterlist_append(list, p);
635 
636  p = cpl_parameter_new_range("sinfoni.illumcorr.urx",
637  CPL_TYPE_INT,
638  "Reference region coordinates ",
639  "sinfoni.illumcorr",
640  60, 0, 63);
641  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-urx");
642  cpl_parameterlist_append(list, p);
643 
644  p = cpl_parameter_new_range("sinfoni.illumcorr.ury",
645  CPL_TYPE_INT,
646  "Reference region coordinates ",
647  "sinfoni.illumcorr",
648  36, 0, 63);
649  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-ury");
650  cpl_parameterlist_append(list, p);
651 
652  p = cpl_parameter_new_enum("sinfoni.illumcorr.smooth0",
653  CPL_TYPE_INT,
654  "Smooth zeroth order terms by fitting "
655  "with polynomial (1),"
656  "with median filter (2) or not (0) ",
657  "sinfoni.illumcorr",
658  0,
659  3, 0, 1, 2);
660  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-smooth0");
661  cpl_parameterlist_append(list, p);
662 
663  p = cpl_parameter_new_value("sinfoni.illumcorr.smooth0_order",
664  CPL_TYPE_INT,
665  "Order of the smoothing polynomial for 0th term",
666  "sinfoni.illumcorr",
667  2);
668  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-smooth_order0");
669  cpl_parameterlist_append(list, p);
670 
671  p = cpl_parameter_new_range("sinfoni.illumcorr.smooth0_size",
672  CPL_TYPE_INT,
673  "Size of the median filter for 0th "
674  "order smoothing ",
675  "sinfoni.illumcorr",
676  51,3, 301);
677  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-smooth0_size");
678  cpl_parameterlist_append(list, p);
679 
680  p = cpl_parameter_new_value("sinfoni.illumcorr.smooth1",
681  CPL_TYPE_BOOL,
682  "Smooth higher (>0) order polynomials ",
683  "sinfoni.illumcorr",
684  TRUE);
685  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-smooth");
686  cpl_parameterlist_append(list, p);
687 
688  p = cpl_parameter_new_value("sinfoni.illumcorr.smooth1_order",
689  CPL_TYPE_INT,
690  "Smoothing order for higher terms ",
691  "sinfoni.illumcorr",
692  2);
693  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"illumcorr-smooth_order");
694  cpl_parameterlist_append(list, p);
695 
696  p = cpl_parameter_new_value("sinfoni.illumcorr.illumcorr_sigma",
697  CPL_TYPE_DOUBLE,
698  "Reject all fits for which the rms is "
699  "illumcorr-sigma times bigger than the "
700  "median rms in each spectral bin" ,
701  "sinfoni.illumcorr",
702  5.0);
703  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
704  "illumcorr-illumcorr_sigma");
705  cpl_parameterlist_append(list, p);
706 
707 }
708 
709 static int
710 create_illumcorr (const char* plugin_id,
711  cpl_parameterlist *cpl_cfg,
712  cpl_frameset* sof,
713  const char *name_i)
714 {
715  cpl_parameter *p=NULL;
716  double min_flux=0;
717  double sigma=0;
718  double il_sigma=0;
719  int spec_bin=0;
720  int _order=0;
721  cpl_imagelist *sky=NULL;
722  cpl_imagelist *binnedsky=NULL;
723  cpl_imagelist *result=NULL;
724  cpl_image *temp_image=NULL;
725  cpl_image *temp_image2=NULL;
726  int nplanes=0;
727  int i=0;
728  int j=0;
729  int k=0;
730  int kk=0;
731  int n=0;
732  int slitlet=0;
733  int bin=0;
734  double *median=NULL;
735  double *pos=NULL;
736  double temp=0;
737  double temp2=0;
738  double *inter_pos=NULL;
739  double *inter_val=NULL;
740  double *plane_pos=NULL;
741  double *plane_val=NULL;
742  int llx=0;
743  int lly=0;
744  int urx=0;
745  int ury=0;
746  int smooth_order=0;
747  int iter=0;
748  cpl_vector *row=NULL;
749  cpl_vector *model=NULL;
750  cpl_vector *xpos=NULL;
751  cpl_vector *tempvector=NULL;
752  cpl_vector *tempvector2=NULL;
753  double mse=0.0;
754  double stddev=0.0;
755  cpl_polynomial*poly=NULL;
756  cpl_polynomial *poly2=NULL;
757  double *temparray=NULL;
758  double *tempxarray=NULL;
759  double * tempsarray=NULL;
760  cpl_polynomial**coeffs=NULL;
761  float *data=NULL;
762  double *rms_values=NULL;
763  double rms_array[32];
764  int smooth=0;
765  int smooth0=0;
766  int smooth_order0=0;
767  int smooth_size0=0;
768  int center_bins = 0;
769 
770  int *bin_start=NULL;
771  int *bin_end=NULL;
772  int z1=0;
773  int z2=0;
774  int nbins=0;
775 
776  FILE *dumpfile=NULL;
777 
778  int order[32];
779  int ok[64];
780  int nbad=0;
781 
782 
783  /*
784  * Get parameters
785  */
786  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.spec_bin");
787  spec_bin = cpl_parameter_get_int(p);
788  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.min_flux");
789  min_flux = cpl_parameter_get_double(p);
790  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.order");
791  _order = cpl_parameter_get_int(p);
792  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.sigma");
793  sigma = cpl_parameter_get_double(p);
794  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.llx");
795  llx = cpl_parameter_get_int(p);
796  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.lly");
797  lly = cpl_parameter_get_int(p);
798  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.urx");
799  urx = cpl_parameter_get_int(p);
800  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.ury");
801  ury = cpl_parameter_get_int(p);
802  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.illumcorr_sigma");
803  il_sigma = cpl_parameter_get_double(p);
804 
805  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.smooth0");
806  smooth0 = cpl_parameter_get_int (p);
807  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.smooth0_order");
808  smooth_order0 = cpl_parameter_get_int (p);
809  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.smooth0_size");
810  smooth_size0 = cpl_parameter_get_int (p);
811 
812  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.smooth1");
813  smooth = cpl_parameter_get_bool (p);
814  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.smooth1_order");
815  smooth_order = cpl_parameter_get_int (p);
816 
817  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.iterations");
818  iter = cpl_parameter_get_int (p);
819 
820  p = cpl_parameterlist_find(cpl_cfg, "sinfoni.illumcorr.center_bins");
821  center_bins = cpl_parameter_get_bool (p);
822 
823  /* cpl_msg_set_level(CPL_MSG_DEBUG); */
824 
825  /*
826  * Allocate resources
827  */
828  sky = cpl_imagelist_load(name_i, CPL_TYPE_FLOAT, 0);
829  nplanes = cpl_imagelist_get_size(sky);
830 
831  /* Determine the start and end points of data within the
832  * reference region */
833  z1 = 0;
834  z2=nplanes -1;
835  while (z1<nplanes
836  && isnan(cpl_image_get_mean_window(cpl_imagelist_get(sky, z1),
837  llx, lly, urx, ury)))
838  z1++;
839  while (z2>=0
840  && isnan(cpl_image_get_mean_window(cpl_imagelist_get(sky, z2),
841  llx, lly, urx, ury)))
842  z2--;
843  z1 += 2;
844  z2 -= 2;
845  if (z1>=nplanes || z2 <0 || z2<=z1) {
846  sinfo_msg_error ("Start z = %d, end z = %d", z1, z2);
847  cpl_imagelist_delete (sky);
848  return (-1);
849  }
850  sinfo_msg ("Start z = %d, end z = %d", z1, z2);
851 
852  binnedsky = cpl_imagelist_new ();
853  median = (double*) cpl_calloc(nplanes/spec_bin, sizeof(double));
854  pos = (double*) cpl_calloc(nplanes/spec_bin, sizeof(double));
855  temparray = (double*) cpl_calloc(64, sizeof(double));
856  tempxarray= (double*) cpl_calloc(64, sizeof(double));
857  tempsarray= (double*) cpl_calloc (nplanes/spec_bin, sizeof(double));
858  plane_pos = (double*) cpl_calloc (nplanes/spec_bin, sizeof(double));
859  plane_val = (double*) cpl_calloc (nplanes/spec_bin, sizeof(double));
860  coeffs = (cpl_polynomial**) cpl_calloc(32*(nplanes/spec_bin),
861  sizeof(cpl_polynomial*));
862  rms_values= (double*) cpl_calloc (32*(nplanes/spec_bin), sizeof (double));
863  inter_pos = (double*) cpl_calloc (nplanes, sizeof(double));
864  inter_val = (double*) cpl_calloc (nplanes, sizeof(double));
865 
866  model = cpl_vector_new(64);
867  xpos = cpl_vector_new(64);
868 
869  for (i=0; i<64; i++)
870  cpl_vector_set(xpos, i, (double)(i)-((double)urx-(double)llx)/2.0);
871  for (i=0; i<nplanes; i++)
872  inter_pos[i] = (double)i;
873 
874  /*
875  * This array could be given as input file for the recipe.
876  * Generally, 0th order fitting is sufficient (and of course
877  * more robust), but few slitlets might require 1st order.
878  */
879  for (i=0; i<32; i++)
880  order[i] = _order;
881 
882 
883  if (center_bins == 1) {
884  sinfo_msg("Using centering on emission features\n");
885  nbins = sinfo_illumcorr_create_bins (sky,llx, lly, urx, ury,
886  spec_bin, min_flux,
887  &bin_start, &bin_end,
888  z1, z2);
889  }
890  else {
891  sinfo_msg("Using simple spectral binning - "
892  "not centering on emission features\n");
893  nbins = (z2-z1)/spec_bin;
894  bin_start = (int*)cpl_calloc(nbins+1, sizeof(int));
895  bin_end = (int*)cpl_calloc(nbins+1, sizeof(int));
896  for (i = 0; i<nbins; i++) {
897  bin_start[i] = z1+i*spec_bin;
898  bin_end[i] = z1+(i+1)*spec_bin - 1;
899  }
900  if (bin_end[nbins-1]<z2-spec_bin/10) {
901  bin_start[nbins] = bin_end[nbins-1]+1;
902  bin_end[nbins] = z2;
903  nbins++;
904  }
905  }
906 
907  /*
908  * - bin the cube in spectral direction
909  * - calculate the median (=reference value) in region
910  * (llx,lly) - (urx,ury)
911  * - calculate the weighted position of the each spectral bin
912  */
913  sinfo_msg("Binning the cube and calculating statistics\n");
914  for (i=0; i<nbins; i++) {
915  temp_image = cpl_image_duplicate(cpl_imagelist_get(sky, bin_start[i]));
916  median[i] = sinfo_image_get_median_window (temp_image, llx, lly, urx, ury);
917  pos[i] = median[i] * (double)bin_start[i];
918  cpl_imagelist_set (binnedsky, temp_image, i);
919  for (j=bin_start[i]+1; j<bin_end[i]; j++) {
920  temp_image2 = cpl_imagelist_get (sky, j);
921  cpl_image_add (temp_image, temp_image2);
922  temp = sinfo_image_get_median_window (temp_image2, llx, lly, urx, ury);
923  median[i] = median[i] + temp;
924  pos[i] = pos[i] + temp*(double)j;
925  }
926  temp2 =(double)(bin_end[i]-bin_start[i]+1);
927  cpl_image_divide_scalar (temp_image, temp2);
928  pos[i] = pos[i]/median[i];
929  median[i] = median[i] / temp2;
930  sinfo_msg_debug("median image=%g at %g",median[i], pos[i]);
931  }
932 
933  sinfo_msg("Fitting slitlets between x=%d - x=%d\n", llx, urx);
934  sinfo_msg("Fitting order %d\n", _order);
935  for (k=0;k<nbins; k++) {
936  if (median[k]>min_flux) {
937  for (j=0; j<32; j++) {
938  row=cpl_vector_new_from_image_row(cpl_imagelist_get(binnedsky,k),2*j+1);
939  n = 0;
940  for (i=llx; i<=urx; i++) {
941  if (!isnan(cpl_vector_get(row, i))) {
942  ok[i] = 1;
943  temparray[n] = cpl_vector_get(row, i);
944  tempxarray[n] = cpl_vector_get(xpos, i);
945  n++;
946  }
947  else
948  ok[i] = 0;
949  }
950 
951  /* The ends of cube are always filled with NaNs => n==0*/
952  if (n>20) {
953  tempvector = cpl_vector_wrap (n, temparray);
954  tempvector2= cpl_vector_wrap (n, tempxarray);
955  poly = cpl_polynomial_fit_1d_create (tempvector2, tempvector,
956  order[j], &mse);
957 
958  if (poly == NULL)
959  sinfo_msg("Fitting failed (plane %d, row %d): %s",
960  k, j, (char* ) cpl_error_get_message());
961  else {
962  if (sigma>0 && iter>0) {
963  for (kk = 0; kk<iter; kk++) {
964  cpl_vector_fill_polynomial (model, poly, 0.0, 1.0);
965  cpl_vector_subtract (model, row);
966 
967  /* Calculate stdev NaN-correctly */
968  n = 0;
969  for (i=llx; i<=urx; i++)
970  if (ok[i] == 1)
971  temparray[n++] = cpl_vector_get(model, i);
972  stddev = cpl_vector_get_stdev(tempvector);
973 
974  for (i=llx; i<=urx; i++)
975  if (ok[i] == 1)
976  if (fabs(cpl_vector_get(model, i))>(stddev*sigma))
977  ok[i] = 0;
978 
979 
980  n = 0;
981  for (i=llx; i<=urx; i++) {
982  if (ok[i] == 1) {
983  temparray[n] = cpl_vector_get(row, i);
984  tempxarray[n] = cpl_vector_get(xpos, i);
985  n++;
986  }
987  }
988  cpl_polynomial_delete(poly);
989  if (n>20) {
990  cpl_vector_unwrap (tempvector);
991  cpl_vector_unwrap (tempvector2);
992  tempvector = cpl_vector_wrap (n, temparray);
993  tempvector2= cpl_vector_wrap (n, tempxarray);
994  stddev = cpl_vector_get_stdev(tempvector);
995 
996  poly = cpl_polynomial_fit_1d_create (tempvector2,
997  tempvector,
998  order[j], &mse);
999  if (poly == NULL)
1000  break;
1001  }
1002  else {
1003  poly = NULL;
1004  break;
1005  }
1006  /* printf ("%d %e ", n, stddev); */
1007  }
1008  }
1009 
1010  if (poly!=NULL) {
1011  coeffs[j*nbins+k] = poly;
1012  rms_values[j*nbins+k] = sqrt(mse);
1013  }
1014  else
1015  coeffs[j*nbins+k] = NULL;
1016  }
1017  cpl_vector_unwrap (tempvector);
1018  cpl_vector_unwrap (tempvector2);
1019  }
1020  cpl_vector_delete(row);
1021  }
1022  }
1023  }
1024 
1025  /*
1026  * These should (probably) be saved in a fits file...
1027  */
1028  sinfo_msg("Writing dat out_illum.dat\n");
1029  dumpfile = fopen ("out_illum.dat","w");
1030  fprintf (dumpfile, "# slitlet, pos, median, rms, coeff0, coeff1...\n");
1031  for (slitlet = 0; slitlet<32; slitlet++)
1032  for (bin=0; bin<nbins; bin++) {
1033  poly = coeffs[slitlet*nbins+bin];
1034  if (poly != NULL) {
1035  fprintf (dumpfile, "%d %f %f %f ",slitlet, pos[bin],
1036  median[bin],
1037  rms_values[slitlet*nbins+bin]);
1038  for (i=0; i<(cpl_polynomial_get_degree(poly)+1); i++) {
1039  temp = cpl_polynomial_get_coeff (poly, &i);
1040  fprintf (dumpfile, "%f ", temp);
1041  }
1042  fprintf (dumpfile, "\n");
1043  }
1044  }
1045  fclose (dumpfile);
1046 
1047  /*
1048  * Remove poor fits:
1049  * - calculate the median rms of all fits
1050  * - throw away the fits whose rms is il_sigma*median_rms
1051  */
1052  sinfo_msg("Removing poor fits - factor %f", il_sigma);
1053  n = 0;
1054  i = 0;
1055  nbad=0;
1056  sinfo_msg("max loop over bin =%d",nbins);
1057  for (bin=0; bin<nbins; bin++) {
1058  k = 0;
1059  for (slitlet=0; slitlet<32; slitlet++)
1060  if (coeffs[slitlet*nbins+bin] != NULL)
1061  rms_array[k++] = rms_values[slitlet*nbins+bin];
1062  if (k>0) {
1063  /* For some bizarre reason, cpl_tools_get_median_double returns
1064  * -1076245448.000000 (is that NaN?). On closer inspection,
1065  * it seems to have replaced one of the numbers in array with NaN...*/
1066  tempvector = cpl_vector_wrap (k, &rms_array[0]);
1067  temp = cpl_vector_get_median (tempvector);
1068  sinfo_msg("median temp=%g",temp);
1069  cpl_vector_unwrap (tempvector);
1070  for (slitlet=0; slitlet<32; slitlet++)
1071  if (coeffs[slitlet*nbins+bin] != NULL) {
1072  i++;
1073  if (rms_values[slitlet*nbins+bin]>(il_sigma*temp)) {
1074  cpl_polynomial_delete(coeffs[slitlet*nbins+bin]);
1075  coeffs[slitlet*nbins+bin] = NULL;
1076  n++;
1077  }
1078  } else {
1079  nbad++;
1080  }
1081 
1082  }
1083  }
1084  sinfo_msg("Removed %d poor fits out of %d. Bad coeffs=%d", n,i,nbad);
1085 
1086  if(smooth0 == 1) {
1087  sinfo_msg("Smoothing zeroth terms (order %d)", smooth_order0);
1088  /*
1089  * Since the new centering scheme will pro
1090  */
1091  for (slitlet = 0; slitlet<32; slitlet++) {
1092  k = 0;
1093  for (bin=0; bin<nbins; bin++) {
1094  if (coeffs[slitlet*nbins+bin] != NULL) {
1095  poly = coeffs[slitlet*nbins+bin];
1096  i = 0;
1097  temp = cpl_polynomial_get_coeff (poly, &i);
1098  plane_pos[k] = pos[bin];
1099  plane_val[k] = temp/median[bin];
1100  k++;
1101  }
1102  }
1103  if (k>0) {
1104  tempvector = cpl_vector_wrap (k, plane_pos);
1105  tempvector2= cpl_vector_wrap (k, plane_val);
1106  poly2 = cpl_polynomial_fit_1d_create (tempvector, tempvector2,
1107  smooth_order0, &mse);
1108  cpl_vector_unwrap (tempvector);
1109  cpl_vector_unwrap (tempvector2);
1110  for (bin=0; bin<nbins; bin++) {
1111  if (coeffs[slitlet*nbins+bin] != NULL) {
1112  poly = coeffs[slitlet*nbins+bin];
1113  i = 0;
1114  temp2 = cpl_polynomial_eval_1d (poly2, pos[bin], NULL);
1115  cpl_polynomial_set_coeff (poly, &i, temp2*median[bin]);
1116  }
1117  }
1118  cpl_polynomial_delete(poly2);
1119  }
1120  else
1121  sinfo_msg_warning ("Not enough data points in slitlet %d", slitlet);
1122  }
1123  }
1124  else if (smooth0 == 2) {
1125  sinfo_msg("Smoothing zeroth terms (median filter size %d)", smooth_size0);
1126  smooth_size0 = smooth_size0/2;
1127  if (smooth_size0 <= 0) smooth_size0 = 1;
1128  for (slitlet = 0; slitlet<32; slitlet++) {
1129  k = 0;
1130  for (bin=0; bin<nbins; bin++) {
1131  if (coeffs[slitlet*nbins+bin] != NULL) {
1132  poly = coeffs[slitlet*nbins+bin];
1133  i = 0;
1134  temp = cpl_polynomial_get_coeff (poly, &i);
1135  //plane_pos[k] = pos[bin];
1136  plane_val[k] = temp/median[bin];
1137  k++;
1138  }
1139  }
1140  if (k>0) {
1141  tempvector = cpl_vector_wrap (k, plane_val);
1142  tempvector2= sinfo_juha_vector_filter_median_create (tempvector,
1143  smooth_size0);
1144  cpl_vector_unwrap (tempvector);
1145  kk = 0;
1146  for (bin=0; bin<nbins; bin++) {
1147  if (coeffs[slitlet*nbins+bin] != NULL) {
1148  poly = coeffs[slitlet*nbins+bin];
1149  i = 0;
1150  cpl_polynomial_set_coeff(poly, &i, cpl_vector_get(tempvector2, kk++)
1151  *median[bin]);
1152  }
1153  }
1154  cpl_vector_delete (tempvector2);
1155  }
1156  }
1157  }
1158 
1159  if(smooth == 1) {
1160  sinfo_msg("Smoothing higher terms (with order %d)", smooth_order);
1161  for (slitlet = 0; slitlet<32; slitlet++) {
1162  if (order[slitlet]>0) {
1163  for (j=1; j<=order[slitlet]; j++) {
1164  k = 0;
1165  for (bin=0; bin<nbins; bin++) {
1166  if (coeffs[slitlet*nbins+bin] != NULL) {
1167  poly = coeffs[slitlet*nbins+bin];
1168  i = 0;
1169  /* temp = cpl_polynomial_get_coeff (poly, &i); */
1170  temp2 = cpl_polynomial_get_coeff (poly, &j);
1171  plane_pos[k] = pos[bin];
1172  plane_val[k] = temp2/median[bin];
1173  k++;
1174  }
1175  }
1176  if (k>0) {
1177  tempvector = cpl_vector_wrap (k, plane_pos);
1178  tempvector2= cpl_vector_wrap (k, plane_val);
1179  poly2 = cpl_polynomial_fit_1d_create (tempvector, tempvector2,
1180  smooth_order, &mse);
1181  cpl_vector_unwrap (tempvector);
1182  cpl_vector_unwrap (tempvector2);
1183  for (bin=0; bin<nbins; bin++) {
1184  if (coeffs[slitlet*nbins+bin] != NULL) {
1185  poly = coeffs[slitlet*nbins+bin];
1186  i = 0;
1187  /* temp = cpl_polynomial_get_coeff (poly, &i); */
1188  temp2 = cpl_polynomial_eval_1d (poly2, pos[bin], NULL);
1189  cpl_polynomial_set_coeff (poly, &j, temp2*median[bin]);
1190  }
1191  }
1192  cpl_polynomial_delete(poly2);
1193  }
1194  else
1195  sinfo_msg_warning ("Not enough data points in slitlet %d\n",
1196  slitlet);
1197  }
1198  }
1199  }
1200  }
1201 
1202  sinfo_msg("Creating cube for illumination correction\n");
1203  result = cpl_imagelist_new ();
1204  for (i=0; i<nplanes; i++) {
1205  temp_image = cpl_image_new (64, 64, CPL_TYPE_FLOAT);
1206  cpl_imagelist_set (result, temp_image, i);
1207  }
1208 
1209  sinfo_msg("nplanes=%d spec_bin=%d",nplanes,spec_bin);
1210  if ( nbins>5) {
1211  sinfo_msg("Interpolating\n");
1212  for (slitlet = 0; slitlet<32; slitlet++) {
1213  for (i=0; i<64; i++) {
1214  k = 0;
1215  for (bin=0; bin<nbins; bin++) {
1216  if (coeffs[slitlet*nbins+bin] != NULL) {
1217  plane_pos[k] = pos[bin];
1218  plane_val[k] = cpl_polynomial_eval_1d(coeffs[slitlet*nbins+bin],
1219  cpl_vector_get(xpos, i),NULL)/
1220  median[bin];
1221  k++;
1222  }
1223  }
1224 
1225  if (k>3) {
1226  sinfo_juha_function1d_natural_spline (plane_pos, plane_val, k,
1227  &inter_pos[(int)plane_pos[0]],
1228  &inter_val[(int)plane_pos[0]],
1229  (int)(plane_pos[k-1]-plane_pos[0]));
1230  for (j=0; j<=(int)plane_pos[0]; j++)
1231  inter_val[j] = inter_val[(int)plane_pos[0]+1];
1232  for (j=(int)plane_pos[k-1]-1; j<nplanes; j++)
1233  inter_val[j] = inter_val[(int)plane_pos[k-1]-2];
1234  for (k=0; k<nplanes; k++) {
1235  data = cpl_image_get_data_float(cpl_imagelist_get(result, k));
1236  data[i + (2*slitlet)*64] = inter_val[k];
1237  data[i + (2*slitlet+1)*64] = inter_val[k];
1238  /*sinfo_msg("inter_val=%g",inter_val[k]);*/
1239  }
1240  }
1241  else
1242  sinfo_msg_warning ("Too few points %d\n", slitlet);
1243  }
1244  }
1245  }
1246  else if (nbins==1) {
1247  sinfo_msg("Filling the illumination cube\n");
1248  for (slitlet = 0; slitlet<32; slitlet++) {
1249  for (i=0; i<64; i++) {
1250  if (coeffs[slitlet] != NULL) {
1251  temp = cpl_polynomial_eval_1d(coeffs[slitlet],
1252  cpl_vector_get(xpos, i),NULL)/median[0];
1253  for (k=0; k<nplanes; k++) {
1254  data = cpl_image_get_data_float(cpl_imagelist_get(result, k));
1255  data[i + (2*slitlet)*64] = temp;
1256  data[i + (2*slitlet+1)*64] = temp;
1257  sinfo_msg("temp=%g",temp);
1258  }
1259  }
1260  }
1261  }
1262  } else {
1263 
1264  }
1265 
1266 
1267  sinfo_msg("Writing ima out_illum.fits\n");
1268  /* pl = cpl_propertylist_load (name_i, 0); */
1269  /* if (cpl_propertylist_has(pl, KEY_NAME_PRO_CATG)) */
1270  /* cpl_propertylist_set_string (pl, KEY_NAME_PRO_CATG, PRO_ILL_COR); */
1271  /* else */
1272  /* cpl_propertylist_append_string (pl, KEY_NAME_PRO_CATG, PRO_ILL_COR); */
1273 
1274  /* cpl_imagelist_save(result, "out_illum.fits", CPL_BPP_IEEE_FLOAT, pl, 0); */
1275 
1276  sinfo_pro_save_ims(result,sof,sof,"out_illum.fits",
1277  PRO_ILL_COR,NULL,plugin_id, cpl_cfg);
1278 
1279  /*
1280  * These should (probably) be saved in a fits file...
1281  */
1282  sinfo_msg("Writing dat out_illum2.dat\n");
1283  dumpfile = fopen ("out_illum2.dat","w");
1284  fprintf (dumpfile, "# slitlet, pos, median, rms, coeff0, coeff1...\n");
1285  for (slitlet = 0; slitlet<32; slitlet++)
1286  for (bin=0; bin<nbins; bin++) {
1287  poly = coeffs[slitlet*nbins+bin];
1288  if (poly != NULL) {
1289  fprintf (dumpfile, "%d %f %f %f ",slitlet, pos[bin],
1290  median[bin],
1291  rms_values[slitlet*nbins+bin]);
1292  for (i=0; i<(cpl_polynomial_get_degree(poly)+1); i++) {
1293  temp = cpl_polynomial_get_coeff (poly, &i);
1294  fprintf (dumpfile, "%f ", temp);
1295  }
1296  fprintf (dumpfile, "\n");
1297  }
1298  }
1299  fclose (dumpfile);
1300 
1301  /*
1302  * Clean up...
1303  */
1304  for (i = 0; i<32*nbins; i++)
1305  if (coeffs[i] != NULL)
1306  cpl_polynomial_delete(coeffs[i]);
1307  cpl_imagelist_delete (sky);
1308  cpl_imagelist_delete (binnedsky);
1309  cpl_imagelist_delete (result);
1310  cpl_free (pos);
1311  cpl_free (median);
1312  cpl_free (temparray);
1313  cpl_free (tempxarray);
1314  cpl_free (tempsarray);
1315  cpl_free (coeffs);
1316  cpl_free (inter_pos);
1317  cpl_free (inter_val);
1318  cpl_free (plane_pos);
1319  cpl_free (plane_val);
1320  cpl_free (rms_values);
1321  cpl_vector_delete (xpos);
1322  cpl_vector_delete (model);
1323 
1324  cpl_free (bin_start);
1325  cpl_free (bin_end);
1326 
1327  return (1);
1328 }
1329 
1330 /*
1331  * sinfo_illumcorr_create_bins:
1332  * - searches for the sky emission lines
1333  * - increases the size of the bin to include two or more emission
1334  * lines if they are too close to each other
1335  * - fills the space between emission lines with bins if
1336  * thermal background has enough flux
1337  * - copies the start and end points of bins to two arrays
1338  * (returned in **start and **end)
1339  *
1340  * Returns: the number bins created
1341  *
1342  * The arrays start and end must be deallocated with cpl_free()
1343  */
1344 static int
1345 sinfo_illumcorr_create_bins (cpl_imagelist *sky,
1346  int llx, int lly, int urx, int ury,
1347  int spec_bin,
1348  double min_flux,
1349  int ** start,
1350  int ** end,
1351  int z1, int z2)
1352 {
1353  int temp_i=0;
1354  double testarray3[15];
1355  double temp_double=0;
1356  int i=0, j=0, k=0,kk=0,nplanes=0;
1357 
1358  int norig = 0, nmerged = 0, ncont = 0, nline=0;
1359 
1360  int *pos=NULL;
1361  int *x1=NULL;
1362  int *x2=NULL;
1363  int *x1b=NULL;
1364  int *x2b=NULL;
1365  int *s1=NULL;
1366  int *s2=NULL;
1367  double *flux=NULL;
1368  double *spec=NULL;
1369  double *spec_cont=NULL;
1370  double *spec_line=NULL;
1371 
1372 
1373 
1374  nplanes = cpl_imagelist_get_size(sky);
1375 
1376  spec = (double*) cpl_calloc(nplanes, sizeof(double));
1377  spec_line = (double*) cpl_calloc(nplanes, sizeof(double));
1378  spec_cont = (double*) cpl_calloc(nplanes, sizeof(double));
1379 
1380  /* there should be no way of actually needing this large arrays*/
1381  pos = (int*) cpl_calloc(nplanes, sizeof(int));
1382  flux = (double*) cpl_calloc(nplanes, sizeof(double));
1383  x1 = (int*) cpl_calloc(nplanes, sizeof(int));
1384  x2 = (int*) cpl_calloc(nplanes, sizeof(int));
1385  x1b = (int*) cpl_calloc(nplanes, sizeof(int));
1386  x2b = (int*) cpl_calloc(nplanes, sizeof(int));
1387 
1388  for (i=z1; i<=z2; i++) {
1389  cpl_image* temp_image = cpl_imagelist_get(sky, i);
1390  spec[i] = sinfo_image_get_median_window (temp_image, llx, lly, urx, ury);
1391  }
1392  for (i=z1+7; i<=z2-7; i++) {
1393  k = 0;
1394  for (j=-7; j<=7; j++)
1395  if (!isnan(spec[i+j]))
1396  testarray3[k++] = spec[i+j];
1397  if (k>0) {
1398  sinfo_tools_sort_double (&testarray3[0], k);
1399  spec_cont[i] = testarray3[1];
1400  }
1401  else
1402  spec_cont[i] = 0./0.;
1403  }
1404 
1405  sinfo_msg_debug("Calculating pure line flux at pos: "
1406  "original, continuum, line");
1407  for (i=z1; i<=z2; i++) {
1408  spec_line[i] = spec[i] - spec_cont[i];
1409  sinfo_msg_debug("Flux at %i = %g %g %g",
1410  i,spec[i],spec_cont[i], spec_line[i]);
1411  }
1412 
1413 
1414  /*
1415  * Search for peaks
1416  */
1417  sinfo_msg ("Searching for peaks");
1418  temp_double = -10000.0;
1419  i = z1+2;
1420  while (i<=z2-2) {
1421  if (!isnan (spec_line[i])) {
1422  if (temp_double<spec_line[i]) {
1423  temp_i = i;
1424  temp_double = spec_line[i];
1425  }
1426  else {
1427  /* Found a peak! */
1428  if (temp_i == i-1 && spec_line[temp_i]>min_flux) {
1429  k = 0;
1430  for (j=-spec_bin/2; j<=spec_bin/2; j++)
1431  if (j+i>=0 && i+j<nplanes && isnan(spec[i+j])) {
1432  k = 1;
1433  break;
1434  }
1435  if (k==0) {
1436  pos[norig] = temp_i; // - spec_bin/2;
1437  flux[norig] = temp_double;
1438  x1[norig] = temp_i;
1439  x2[norig] = temp_i;
1440  temp_double = -10000.0;
1441  while (spec_line[i]<spec_line[i-1])
1442  i++;
1443  i--;
1444  norig++;
1445  }
1446  }
1447  }
1448  }
1449  i++;
1450  }
1451 
1452  /*
1453  * Merge the features which are too close to each other
1454  */
1455  sinfo_msg ("Merging emission features too close to each other");
1456  i = 0;
1457  while (i<norig) {
1458  if (flux[i] > 0.0) {
1459  j = i+1;
1460  while (j<norig
1461  && (x1[j]-x2[i]) <=spec_bin
1462  && flux[j]>0.0) {
1463  flux[j] = -100.0;
1464  x2[i] = x1[j];
1465  j++;
1466  nmerged++;
1467  }
1468  }
1469  i++;
1470  }
1471 
1472  nline = norig - nmerged;
1473 
1474  j = 0;
1475  for (i=0; i<norig; i++)
1476  if (flux[i]>0.0) {
1477  x1b[j] = x1[i] - spec_bin/2;
1478  x2b[j] = x2[i] + spec_bin/2;
1479  j++;
1480  /* sinfo_msg ("Bin start: %i end %i", x1[i], x2[i]); */
1481  }
1482 
1483  x1b[j] = nplanes+1;
1484 
1485  /*
1486  * Check whether there is enough continuum (thermal background)
1487  * for binning
1488  */
1489  j=0;
1490  i=z1;
1491  while (i<=z2) {
1492  if (!isnan (spec[i])) {
1493  if (x1b[j]-i < spec_bin) {
1494  i = x2b[j]+1;
1495  j++;
1496  }
1497  else {
1498  kk = 0;
1499  for (k=0; k<spec_bin; k++)
1500  if (spec[i+k]>min_flux)
1501  kk++;
1502  if (kk==spec_bin) {
1503  x1[ncont] = i;
1504  x2[ncont] = i+spec_bin-1;
1505  ncont++;
1506  i = i+spec_bin;
1507  }
1508  else
1509  i++;
1510  }
1511  }
1512  else
1513  i++;
1514  }
1515 
1516  sinfo_msg ("Number of bins centered on emission features:");
1517  sinfo_msg (" %i - %i (merged) = %i", norig, nmerged, nline);
1518  sinfo_msg (" %i continuum bins", ncont);
1519 
1520  s1 = (int*)cpl_calloc(norig-nmerged+ncont, sizeof(int));
1521  s2 = (int*)cpl_calloc(norig-nmerged+ncont, sizeof(int));
1522 
1523 
1524  /*
1525  * Merge arrays sorted
1526  */
1527  i=0;
1528  j=0;
1529  k=0;
1530  while (k<norig-nmerged+ncont) {
1531  if (i<norig && j<ncont && x1b[i]<x1[j]) {
1532  s1[k] = x1b[i];
1533  s2[k] = x2b[i];
1534  k++;
1535  i++;
1536  }
1537  else if (i<norig && j<ncont && x1b[i]>x1[j]) {
1538  s1[k] = x1[j];
1539  s2[k] = x2[j];
1540  k++;
1541  j++;
1542  }
1543  else if (i == norig) {
1544  s1[k] = x1[j];
1545  s2[k] = x2[j];
1546  k++;
1547  j++;
1548  }
1549  else if (j == ncont) {
1550  s1[k] = x1b[i];
1551  s2[k] = x2b[i];
1552  k++;
1553  i++;
1554  }
1555  else {
1556  /* Should never happen */
1557  sinfo_msg_warning("Something went wrong when combining "
1558  "the bins %i and %i", i,j);
1559  break;
1560  }
1561  }
1562 
1563  for (i=0; i<nline+ncont; i++)
1564  sinfo_msg_debug ("Bin start: %i end %i", s1[i], s2[i]);
1565 
1566  *start = s1;
1567  *end = s2;
1568 
1569  cpl_free (pos);
1570  cpl_free (x1);
1571  cpl_free (x2);
1572  cpl_free (x1b);
1573  cpl_free (x2b);
1574  cpl_free (flux);
1575  cpl_free (spec);
1576  cpl_free (spec_line);
1577  cpl_free (spec_cont);
1578 
1579  return (nline+ncont);
1580 }
1581 
1582 
1583 /*-------------------------------------------------------------------------*/
1610 /*--------------------------------------------------------------------------*/
1611 
1612 static int
1613 sinfo_juha_function1d_natural_spline(
1614  double * x,
1615  double * y,
1616  int len,
1617  double * splX,
1618  double * splY,
1619  int splLen
1620 )
1621 {
1622  int end;
1623  int loc, found;
1624  register int i, j, n;
1625  double * h; /* vector of deltas in x */
1626  double * alpha;
1627  double * l,
1628  * mu,
1629  * z,
1630  * a,
1631  * b,
1632  * c,
1633  * d;
1634 
1635  end = len - 1;
1636 
1637  a = cpl_malloc(sizeof(double) * splLen * 9) ;
1638  b = a + len;
1639  c = b + len;
1640  d = c + len;
1641  h = d + len;
1642  l = h + len;
1643  z = l + len;
1644  mu = z + len;
1645  alpha = mu + len;
1646 
1647  for (i = 0; i < len; i++) {
1648  a[i] = (double)y[i];
1649  }
1650 
1651  /* Calculate vector of differences */
1652  for (i = 0; i < end; i++) {
1653  h[i] = (double)x[i + 1] - (double)x[i];
1654  if (h[i] < 0.0) {
1655  cpl_free(a) ;
1656  return -1;
1657  }
1658  }
1659 
1660  /* Calculate alpha vector */
1661  for (n = 0, i = 1; i < end; i++, n++) {
1662  /* n = i - 1 */
1663  alpha[i] = 3.0 * ((a[i+1] / h[i]) - (a[i] / h[n]) - (a[i] / h[i]) +
1664  (a[n] / h[n]));
1665  }
1666 
1667  /* Vectors to solve the tridiagonal matrix */
1668  l[0] = l[end] = 1.0;
1669  mu[0] = mu[end] = 0.0;
1670  z[0] = z[end] = 0.0;
1671  c[0] = c[end] = 0.0;
1672 
1673  /* Calculate the intermediate results */
1674  for (n = 0, i = 1; i < end; i++, n++) {
1675  /* n = i-1 */
1676  l[i] = 2 * (h[i] + h[n]) - h[n] * mu[n];
1677  mu[i] = h[i] / l[i];
1678  z[i] = (alpha[i] - h[n] * z[n]) / l[i];
1679  }
1680  for (n = end, j = end - 1; j >= 0; j--, n--) {
1681  /* n = j + 1 */
1682  c[j] = z[j] - mu[j] * c[n];
1683  b[j] = (a[n] - a[j]) / h[j] - h[j] * (c[n] + 2.0 * c[j]) / 3.0;
1684  d[j] = (c[n] - c[j]) / (3.0 * h[j]);
1685  }
1686 
1687  /* Now calculate the new values */
1688  for (j = 0; j < splLen; j++) {
1689  double v = (double)splX[j];
1690  splY[j] = (float)0;
1691 
1692  /* Is it outside the interval? */
1693  if ((v < (double)x[0]) || (v > (double)x[end])) {
1694  continue;
1695  }
1696  /* Search for the interval containing v in the x vector */
1697  loc = sinfo_function1d_search_value(x, len, (double)v, &found);
1698  if (found) {
1699  splY[j] = y[loc];
1700  } else {
1701  loc--;
1702  v -= (double)x[loc];
1703  splY[j] = (float)( a[loc] + v * (b[loc] + v * (c[loc] + v * d[loc])));
1704  }
1705  }
1706  cpl_free(a) ;
1707  return 0;
1708 }
1709 
1710 /*-------------------------------------------------------------------------*/
1726 /*--------------------------------------------------------------------------*/
1727 
1728 static int
1729 sinfo_function1d_search_value(
1730  double * x,
1731  int len,
1732  double key,
1733  int * foundPtr
1734 )
1735 {
1736 
1737  int low = 0;
1738  int high = len - 1;
1739 
1740  while (high >= low) {
1741  int middle = (high + low) / 2;
1742  if (key > x[middle]) {
1743  low = middle + 1;
1744  } else if (key < x[middle]) {
1745  high = middle - 1;
1746  } else {
1747  *foundPtr = 1;
1748  return (middle);
1749  }
1750  }
1751  *foundPtr = 0;
1752  return (low);
1753 }
1754 
1755 
1756 /*
1757 cpl_vector * sinfo_vector_filter_median_create(
1758  const cpl_vector * v,
1759  int hw)
1760 {
1761  cpl_vector * filtered;
1762  double * row;
1763  int i, j, k, size;
1764  double temp;
1765 
1766  size = cpl_vector_get_size(v);
1767  filtered = cpl_vector_new(size);
1768 
1769  row = cpl_malloc((2*hw+1) * sizeof(double));
1770  for (i=0; i<size; i++) {
1771  k = 0;
1772  for (j=-hw; j<=hw; j++)
1773  if ( (i+j) >= 0 && (i+j) < size) {
1774  temp = cpl_vector_get (v, i+j);
1775  row[k] = temp;
1776  k++;
1777  }
1778  cpl_tools_sort_double (row, k);
1779  if (k%2 == 1)
1780  temp = row[k/2];
1781  else
1782  temp = row[k/2-1];
1783  cpl_vector_set (filtered, i, temp);
1784  }
1785  cpl_free(row);
1786  return filtered;
1787 }
1788  */
1789 
1790 static cpl_vector *
1791 sinfo_juha_vector_filter_median_create(
1792  const cpl_vector * v,
1793  int hw)
1794 {
1795  cpl_vector * filtered=NULL;
1796  double * row=NULL;
1797  int i, j, size;
1798  double temp;
1799 
1800  size = cpl_vector_get_size(v);
1801  filtered = cpl_vector_new(size);
1802 
1803  row = cpl_malloc((2*hw+1) * sizeof(double));
1804  for (i=0; i<size; i++) {
1805  int k = 0;
1806  for (j=-hw; j<=hw; j++)
1807  if ( (i+j) >= 0 && (i+j) < size) {
1808  temp = cpl_vector_get (v, i+j);
1809  row[k] = temp;
1810  k++;
1811  }
1812  sinfo_tools_sort_double (row, k);
1813 
1814  if (k%2 == 1)
1815  temp = row[k/2];
1816  else
1817  temp = row[k/2-1];
1818  cpl_vector_set (filtered, i, temp);
1819  }
1820  cpl_free(row);
1821  return filtered;
1822 }
1823 
1824 #define CPL_PIX_STACK_SIZE 50
1825 /*---------------------------------------------------------------------------*/
1836 /*---------------------------------------------------------------------------*/
1837 static cpl_error_code sinfo_tools_sort_double(
1838  double * pix_arr,
1839  int n)
1840 {
1841  int i, ir, j, k, l;
1842  int * i_stack ;
1843  int j_stack ;
1844  double a ;
1845 
1846  /* Check entries */
1847  cpl_ensure(pix_arr, CPL_ERROR_NULL_INPUT, CPL_ERROR_NULL_INPUT) ;
1848 
1849  ir = n ;
1850  l = 1 ;
1851  j_stack = 0 ;
1852  i_stack = malloc(CPL_PIX_STACK_SIZE * sizeof(double)) ;
1853  for (;;) {
1854  if (ir-l < 7) {
1855  for (j=l+1 ; j<=ir ; j++) {
1856  a = pix_arr[j-1];
1857  for (i=j-1 ; i>=1 ; i--) {
1858  if (pix_arr[i-1] <= a) break;
1859  pix_arr[i] = pix_arr[i-1];
1860  }
1861  pix_arr[i] = a;
1862  }
1863  if (j_stack == 0) break;
1864  ir = i_stack[j_stack-- -1];
1865  l = i_stack[j_stack-- -1];
1866  } else {
1867  k = (l+ir) >> 1;
1868  SINFO_DOUBLE_SWAP(pix_arr[k-1], pix_arr[l])
1869  if (pix_arr[l] > pix_arr[ir-1]) {
1870  SINFO_DOUBLE_SWAP(pix_arr[l], pix_arr[ir-1])
1871  }
1872  if (pix_arr[l-1] > pix_arr[ir-1]) {
1873  SINFO_DOUBLE_SWAP(pix_arr[l-1], pix_arr[ir-1])
1874  }
1875  if (pix_arr[l] > pix_arr[l-1]) {
1876  SINFO_DOUBLE_SWAP(pix_arr[l], pix_arr[l-1])
1877  }
1878  i = l+1;
1879  j = ir;
1880  a = pix_arr[l-1];
1881  for (;;) {
1882  do i++; while (pix_arr[i-1] < a);
1883  do j--; while (pix_arr[j-1] > a);
1884  if (j < i) break;
1885  SINFO_DOUBLE_SWAP(pix_arr[i-1], pix_arr[j-1]);
1886  }
1887  pix_arr[l-1] = pix_arr[j-1];
1888  pix_arr[j-1] = a;
1889  j_stack += 2;
1890  if (j_stack > CPL_PIX_STACK_SIZE) {
1891  /* Should never reach here */
1892  free(i_stack);
1893  return CPL_ERROR_ILLEGAL_INPUT ;
1894  }
1895  if (ir-i+1 >= j-l) {
1896  i_stack[j_stack-1] = ir;
1897  i_stack[j_stack-2] = i;
1898  ir = j-1;
1899  } else {
1900  i_stack[j_stack-1] = j-1;
1901  i_stack[j_stack-2] = l;
1902  l = i;
1903  }
1904  }
1905  }
1906  free(i_stack) ;
1907  return CPL_ERROR_NONE ;
1908 }
1909 
1910 static cpl_vector *
1911 sinfo_vector_filter_median_create(
1912  const cpl_vector * v,
1913  int hw)
1914 {
1915  cpl_vector * filtered;
1916  cpl_vector * row;
1917  int i, j, size;
1918  double temp;
1919 
1920  /* Create the filtered vector */
1921  size = cpl_vector_get_size(v);
1922  filtered = cpl_vector_new(size);
1923 
1924  /* median filter on all central items */
1925  row = cpl_vector_new((2*hw+1));
1926  for (i=0; i<size; i++) {
1927  int k = 0;
1928  for (j=-hw; j<=hw; j++)
1929  if ( (i+j) >= 0 && (i+j) < size) {
1930  temp = cpl_vector_get (v, i+j);
1931  cpl_vector_set(row,k,temp);
1932  k++;
1933  }
1934  /* this returns ~2e8 when all the values are 1.0....*/
1935  /* temp = cpl_tools_get_median_double(row, k); */
1936  cpl_vector_sort(row, +1);
1937  if (k%2 == 1) {
1938  temp = cpl_vector_get(row,k/2);
1939  }
1940  else {
1941  temp = cpl_vector_get(row,k/2-1);
1942  }
1943 
1944  sinfo_msg("value = %g ", temp);
1945  cpl_vector_set (filtered, i, temp);
1946  }
1947  cpl_vector_delete(row);
1948  return filtered;
1949 }
1950 
1951 /*
1952  * A NaN safe version of cpl_image_get_median_window
1953  */
1954 static double
1955 sinfo_image_get_median_window (const cpl_image *image,
1956  int llx, int lly, int urx, int ury)
1957 {
1958  cpl_image *window;
1959  float *data;
1960  double *array, median;
1961  int size, i,j;
1962 
1963  window = cpl_image_extract (image, llx, lly, urx, ury);
1964  size = (urx-llx+1)*(ury-lly+1);
1965  data = cpl_image_get_data_float(window);
1966 
1967  array = (double*)cpl_calloc ( size, sizeof(double));
1968  j = 0;
1969  for (i=0; i<size; i++)
1970  if (!isnan(data[i]))
1971  array[j++] = data[i];
1972 
1973  if (j>0)
1974  sinfo_tools_sort_double (array, j);
1975 
1976  if (j == 0 || 2*j<size)
1977  median = 0./0.;
1978  else if (j%2 == 1)
1979  median = array[j/2];
1980  else
1981  median = array[j/2-1];
1982 
1983  cpl_image_delete (window);
1984  cpl_free (array);
1985 
1986  return (median);
1987 }
void irplib_reset(void)
Reset IRPLIB state.
#define sinfo_msg_debug(...)
Print a debug message.
Definition: sinfo_msg.h:103
#define sinfo_msg_error(...)
Print an error message.
Definition: sinfo_msg.h:69
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.
#define sinfo_msg_warning(...)
Print an warning message.
Definition: sinfo_msg.h:93