36 #include "omega_recipe.h"
66 static int omega_darkcurrent_create(cpl_plugin *) ;
67 static int omega_darkcurrent_exec(cpl_plugin *) ;
68 static int omega_darkcurrent_destroy(cpl_plugin *) ;
69 static int omega_darkcurrent(cpl_frameset *set,cpl_parameterlist *pars) ;
76 cpl_propertylist *qclist, cpl_type_bpp bitpix,
77 const char *outfile, cpl_frame *product_frame);
78 static void omega_darkcurrent_init(
void);
79 static void omega_darkcurrent_tidy(
void);
96 }omega_darkcurrent_config;
101 const cpl_frame *mbframe;
102 cpl_frameset *darklist;
103 omega_fits *firstdark;
104 cpl_propertylist *eh;
113 #define RECIPE "omega_darkcurrent"
129 cpl_recipe * recipe = cpl_calloc(1,
sizeof(*recipe)) ;
130 cpl_plugin * plugin = &recipe->interface ;
132 cpl_plugin_init(plugin,
134 OMEGA_BINARY_VERSION,
135 CPL_PLUGIN_TYPE_RECIPE,
137 "OMEGA - Measure the dark current and the particle event rate.(Calfile 531).",
138 "The raw dark frames are trimmed, overscan-corrected and"
139 "debiased. The dark current is calculated by median averaging"
140 "three reduced dark frames and iteratively rejecting outliers"
141 "from the result, and computing the mean of the remaining pixels.",
145 omega_darkcurrent_create,
146 omega_darkcurrent_exec,
147 omega_darkcurrent_destroy) ;
149 cpl_pluginlist_append(list, plugin) ;
165 static int omega_darkcurrent_create(cpl_plugin * plugin)
172 if (cpl_error_get_code() != CPL_ERROR_NONE) {
173 cpl_msg_error(cpl_func,
"%s():%d: An error is already set: %s",
174 cpl_func, __LINE__, cpl_error_get_where());
175 return (
int)cpl_error_get_code();
178 if (plugin == NULL) {
179 cpl_msg_error(cpl_func,
"Null plugin");
180 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
184 if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
185 cpl_msg_error(cpl_func,
"Plugin is not a recipe");
186 cpl_ensure_code(0, (
int)CPL_ERROR_TYPE_MISMATCH);
190 recipe = (cpl_recipe *)plugin;
193 recipe->parameters = cpl_parameterlist_new() ;
194 if (recipe->parameters == NULL) {
195 cpl_msg_error(cpl_func,
"Parameter list allocation failed");
196 cpl_ensure_code(0, (
int)CPL_ERROR_ILLEGAL_OUTPUT);
200 p = cpl_parameter_new_value(
"omega.omega_darkcurrent.ExtensionNumber",
202 "FITS extension number to load (1 to 32). (-1 = all)",
206 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ext") ;
207 cpl_parameterlist_append(recipe->parameters, p) ;
210 p = cpl_parameter_new_range(
"omega.omega_darkcurrent.OverscanMethod",
212 "Overscan Correction Method",
215 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"oc-meth") ;
216 cpl_parameterlist_append(recipe->parameters, p) ;
218 p = cpl_parameter_new_value(
"omega.omega_darkcurrent.PAF",
220 "Boolean value to create PAF files. 1(Yes), 0(No)",
224 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
"paf") ;
225 cpl_parameterlist_append(recipe->parameters, p) ;
227 p = cpl_parameter_new_value(
"omega.omega_darkcurrent.RejThre",
229 "The threshold rejecting outlying pixels",
233 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"rej-thre") ;
234 cpl_parameterlist_append(recipe->parameters, p) ;
236 p = cpl_parameter_new_value(
"omega.omega_darkcurrent.DetThre",
238 "The detection threshold for cosmic ray event ",
242 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"det-thre") ;
243 cpl_parameterlist_append(recipe->parameters, p) ;
246 p = cpl_parameter_new_value(
"omega.omega_darkcurrent.MaxIter",
248 "The maximum number of iterations",
252 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"niter") ;
253 cpl_parameterlist_append(recipe->parameters, p) ;
255 p = cpl_parameter_new_value(
"omega.omega_darkcurrent.MaxCurrent",
257 "The maximum dark current in ADU/pixel/hour",
261 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
"maxcur") ;
262 cpl_parameterlist_append(recipe->parameters, p) ;
265 p = cpl_parameter_new_value(
"omega.omega_darkcurrent.MaxDiffCurrent",
267 "The maximum difference of dark current between previous ??",
271 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
"maxdifcur") ;
272 cpl_parameterlist_append(recipe->parameters, p) ;
275 path = cpl_sprintf(
"%s", OMEGA_BIN_PATH);
276 p = cpl_parameter_new_value(
"omega.omega_darkcurrent.BinPath",
278 "Path to any external executable program.",
282 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
"bin-path");
283 cpl_parameterlist_append(recipe->parameters, p);
286 path = cpl_sprintf(
"%s/omega.cosmic.sex", OMEGA_CONFIG_PATH);
287 p = cpl_parameter_new_value(
"omega.omega_darkcurrent.SexCosmic",
289 "Path to Sextractor cosmic detection mode config file.",
293 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
"sex-cosmic");
294 cpl_parameterlist_append(recipe->parameters, p);
297 path = cpl_sprintf(
"%s/omega.conv", OMEGA_CONFIG_PATH);
298 p = cpl_parameter_new_value(
"omega.omega_darkcurrent.SexConv",
300 "Path to Sextractor convolution mask file.",
304 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
"sex-conv");
305 cpl_parameterlist_append(recipe->parameters, p);
308 path = cpl_sprintf(
"%s/omega.param", OMEGA_CONFIG_PATH);
309 p = cpl_parameter_new_value(
"omega.omega_darkcurrent.SexParam",
311 "Path to Sextractor parameters file.",
315 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sex-param");
316 cpl_parameterlist_append(recipe->parameters, p);
319 path = cpl_sprintf(
"%s/omega.nnw", OMEGA_CONFIG_PATH);
320 p = cpl_parameter_new_value(
"omega.omega_darkcurrent.SexNnw",
322 "Path to Sextractor neural network config file.",
326 cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,
"sex-nnw");
327 cpl_parameterlist_append(recipe->parameters, p);
342 static int omega_darkcurrent_exec(cpl_plugin * plugin)
349 if (cpl_error_get_code() != CPL_ERROR_NONE) {
350 cpl_msg_error(cpl_func,
"%s():%d: An error is already set: %s",
351 cpl_func, __LINE__, cpl_error_get_where());
352 return (
int)cpl_error_get_code();
355 if (plugin == NULL) {
356 cpl_msg_error(cpl_func,
"Null plugin");
357 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
361 if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
362 cpl_msg_error(cpl_func,
"Plugin is not a recipe");
363 cpl_ensure_code(0, (
int)CPL_ERROR_TYPE_MISMATCH);
367 recipe = (cpl_recipe *)plugin;
370 if (recipe->parameters == NULL) {
371 cpl_msg_error(cpl_func,
"Recipe invoked with NULL parameter list");
372 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
374 if (recipe->frames == NULL) {
375 cpl_msg_error(cpl_func,
"Recipe invoked with NULL frame set");
376 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
380 recipe_status = omega_darkcurrent(recipe->frames, recipe->parameters);
383 if (cpl_dfs_update_product_header(recipe->frames)) {
384 if (!recipe_status) recipe_status = (int)cpl_error_get_code();
388 return recipe_status;
398 static int omega_darkcurrent_destroy(cpl_plugin * plugin)
402 if (plugin == NULL) {
403 cpl_msg_error(cpl_func,
"Null plugin");
404 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
408 if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
409 cpl_msg_error(cpl_func,
"Plugin is not a recipe");
410 cpl_ensure_code(0, (
int)CPL_ERROR_TYPE_MISMATCH);
414 recipe = (cpl_recipe *)plugin;
416 cpl_parameterlist_delete(recipe->parameters);
430 static int omega_darkcurrent(cpl_frameset *set, cpl_parameterlist *pars)
439 char *outmdark = NULL;
440 const char *_id =
"omega_darkcurrent";
442 cpl_parameter *par = NULL;
443 cpl_frame *firstframe = NULL;
444 cpl_frame *prframe_mdark = NULL;
445 cpl_propertylist *qclist = NULL;
446 cpl_propertylist *alist = NULL;
453 cpl_msg_error (_id,
"Parameters list not found");
457 if (cpl_frameset_is_empty(set) == 1) {
458 cpl_msg_error (_id,
"Frameset not found");
463 par = cpl_parameterlist_find(pars,
"omega.omega_darkcurrent.ExtensionNumber") ;
464 omega_darkcurrent_config.extnum = cpl_parameter_get_int(par) ;
466 par = cpl_parameterlist_find(pars,
"omega.omega_darkcurrent.OverscanMethod") ;
467 omega_darkcurrent_config.oc = cpl_parameter_get_int(par) ;
469 par = cpl_parameterlist_find(pars,
"omega.omega_darkcurrent.PAF");
470 omega_darkcurrent_config.paf = cpl_parameter_get_bool(par);
475 if (oc_dfs_set_groups(set)) {
476 cpl_msg_error(_id,
"Cannot identify RAW and CALIB frames") ;
481 omega_darkcurrent_init();
486 cpl_msg_error(_id,
"Cannot labelise the input frameset");
487 omega_darkcurrent_tidy();
491 DARK_RAW)) == NULL) {
492 cpl_msg_error(_id,
"Cannot find bias frames in input frameset");
493 omega_darkcurrent_tidy();
497 ndark = cpl_frameset_count_tags (set, DARK_RAW);
499 cpl_msg_error (_id,
"Need at least 3 (%s) frames to run this recipe", DARK_RAW);
500 omega_darkcurrent_tidy();
504 cpl_msg_info (_id,
"There are %d %s frames in frame set",ndark, DARK_RAW);
507 firstframe = cpl_frameset_get_position(ps.darklist, 0) ;
512 ps.mbframe = cpl_frameset_find_const(set, OMEGA_CALIB_BIAS);
513 if (ps.mbframe == NULL) {
514 cpl_msg_info(_id,
"A Master Bias is not present in frame set. Using default value %f", bias);
517 cpl_msg_info(_id,
"Using %s %s",OMEGA_CALIB_BIAS, cpl_frame_get_filename(ps.mbframe));
522 if(omega_darkcurrent_config.extnum == 0){
523 cpl_msg_error(cpl_func,
"Unsupported extension request, %d",omega_darkcurrent_config.extnum);
524 omega_darkcurrent_tidy();
529 for (j = jst; j <= jfn; j++) {
531 isfirst = (j == jst);
532 cpl_msg_info(_id,
"Beginning work on extension %d",j);
533 omega_darkcurrent_config.dark_current = 0.0;
534 omega_darkcurrent_config.rate = 0;
538 if(omega_darkcurrent_config.oc==0){
539 if(ps.mbframe != NULL){
541 if(oscan1 != omega_darkcurrent_config.oc) {
542 cpl_msg_warning (_id,
"Overscan correction mode for Master Bias (oc = %d) differs from "
543 "the one used here (oc = %d)", oscan1, omega_darkcurrent_config.oc);
554 cpl_msg_warning(_id,
"Image detector is not live");
556 freefits(ps.firstdark);
560 else if(status == -1){
561 cpl_msg_error(_id,
"Cannot combine images");
563 omega_darkcurrent_tidy();
571 qclist = cpl_propertylist_new();
572 cpl_propertylist_append_double(qclist,
"ESO QC DARK CURRENT",
573 omega_darkcurrent_config.dark_current) ;
574 cpl_propertylist_set_comment(qclist,
"ESO QC DARK CURRENT",
576 cpl_propertylist_append_double(qclist,
"ESO QC PARTICLE RATE",
577 omega_darkcurrent_config.rate) ;
578 cpl_propertylist_set_comment(qclist,
"ESO QC PARTICLE RATE",
579 "Value of particle rate" ) ;
582 outmdark = cpl_sprintf(
"%s_%s.fits", INSTRUME,DARK_PROCATG);
586 alist = cpl_propertylist_new();
587 cpl_propertylist_append_string(alist,
"EXTNAME",
588 cpl_propertylist_get_string(ps.eh,
"EXTNAME"));
589 cpl_propertylist_set_comment(alist,
"EXTNAME",
"Extension name");
591 cpl_propertylist_copy_property_regexp(alist, ps.eh, WCS_KEYS, 0);
593 if(
omega_save_image(ps.mdark,set,pars,alist,qclist,CPL_BPP_IEEE_FLOAT,outmdark,
594 RECIPE,prframe_mdark,NULL,isfirst) == -1){
595 cpl_msg_error(_id,
"Cannot save product %s", DARK_PROCATG);
599 omega_darkcurrent_tidy();
606 freefits(ps.firstdark);
614 omega_darkcurrent_tidy();
639 double dethres = 3.0;
640 double exptime = 0.0;
643 double detector_size_x=1.;
644 double detector_size_y=1.;
645 double detector_size=1.;
647 const char *cmd = NULL;
648 const char *cosmiccat =
"OMEGA_cosmicrays.fits";
649 const char *cosmic_conf = NULL;
650 const char *_id =
"";
651 const char *path = NULL;
652 const char *sex_conv = NULL;
653 const char *sex_nnw = NULL;
654 const char *sex_par = NULL;
655 const char *temp1739 =
"OMEGA_temp001739.fits";
657 const cpl_frame *darkfr = NULL;
658 cpl_image *mbias = NULL, *trim_raw = NULL;
659 cpl_imagelist *ilist = NULL;
660 cpl_stats *stats = NULL;
661 cpl_parameter *par = NULL;
662 cpl_propertylist *mplist = NULL, *xplist = NULL;
665 par = cpl_parameterlist_find(pars,
"omega.omega_darkcurrent.MaxIter") ;
666 maxiter = cpl_parameter_get_int(par) ;
668 par = cpl_parameterlist_find(pars,
"omega.omega_darkcurrent.RejThre") ;
669 rejt = cpl_parameter_get_double(par) ;
671 par = cpl_parameterlist_find(pars,
"omega.omega_darkcurrent.DetThre") ;
672 dethres = cpl_parameter_get_double(par) ;
674 par = cpl_parameterlist_find(pars,
"omega.omega_darkcurrent.BinPath");
675 path = cpl_parameter_get_string(par) ;
677 par = cpl_parameterlist_find(pars,
"omega.omega_darkcurrent.SexCosmic" );
678 cosmic_conf = cpl_parameter_get_string(par) ;
680 par = cpl_parameterlist_find(pars,
"omega.omega_darkcurrent.SexConv" );
681 sex_conv = cpl_parameter_get_string(par) ;
683 par = cpl_parameterlist_find(pars,
"omega.omega_darkcurrent.SexParam" );
684 sex_par = cpl_parameter_get_string(par) ;
686 par = cpl_parameterlist_find(pars,
"omega.omega_darkcurrent.SexNnw" );
687 sex_nnw = cpl_parameter_get_string(par) ;
697 if(ps.mbframe != NULL){
698 mbias = cpl_image_load(cpl_frame_get_filename(ps.mbframe), CPL_TYPE_FLOAT,0,xn);
700 cpl_msg_warning(_id,
"Cannot load image %s", OMEGA_CALIB_BIAS);
704 ilist = cpl_imagelist_new();
705 cpl_msg_info (_id,
"Doing trim and overscan correction on images");
710 ndark = cpl_frameset_get_size(ps.darklist);
712 for (i=0; i< ndark; i++)
714 darkfr = cpl_frameset_get_position(ps.darklist, i);
718 if(trim_raw == NULL){
719 cpl_msg_error(_id,
"Cannot trim image");
724 if(omega_darkcurrent_config.oc==0){
726 cpl_msg_info(cpl_func,
"Subtracting bias frame");
727 cpl_image_subtract(trim_raw, mbias);
730 cpl_image_subtract_scalar(trim_raw, bias);
733 cpl_imagelist_set(ilist, trim_raw, i);
738 cpl_msg_error(_id,
"Error in image list <%s>",cpl_error_get_message());
743 cpl_msg_info (_id,
"Computing the median of all images...");
744 ps.mdark = cpl_imagelist_collapse_median_create(ilist);
746 if (ps.mdark == NULL) {
747 cpl_msg_error (_id,
"Cannot take median of list <%s>",cpl_error_get_message());
752 cpl_msg_info(_id,
"Estimating the RMS using %d maximum iterations",maxiter);
753 cpl_msg_info(_id,
"Rejection threshold is %g (sigma)",rejt);
759 cpl_msg_warning(_id,
"Cannot calculate statistics iteratively");
762 darkfr = cpl_frameset_get_position(ps.darklist, 0) ;
763 mplist = cpl_propertylist_load_regexp(cpl_frame_get_filename(darkfr), 0,
"EXPTIME", 0);
764 xplist = cpl_propertylist_load_regexp(cpl_frame_get_filename(darkfr), xn,
"EXPTIME", 0);
770 omega_darkcurrent_config.dark_current = cpl_stats_get_mean(stats) / exptime*3600.0;
778 for(i=0; i < ndark; i++){
780 cpl_image_save(cpl_imagelist_get(ilist, i),temp1739,BITPIX,NULL,CPL_IO_DEFAULT);
786 cmd = cpl_sprintf(
"%s/sex %s -c %s -PARAMETERS_NAME %s -FILTER_NAME %s -STARNNW_NAME %s "
788 "-CHECKIMAGE_NAME chkimage.fits "
789 "-CATALOG_TYPE FITS_1.0 "
800 if (system(cmd) != 0) {
801 cpl_free((
char *)cmd);
803 cpl_msg_error(
"",
"%s Failed to run Sextractor", _id);
807 cpl_free((
char *)cmd);
809 mplist = cpl_propertylist_load_regexp(cosmiccat, 1,
"NAXIS2", 0);
811 cpl_msg_error(_id,
"Cannot load header for %s",cosmiccat);
816 count = cpl_propertylist_get_int(mplist,
"NAXIS2");
824 detector_size_x=cpl_image_get_size_x(cpl_imagelist_get(ilist,0));
825 detector_size_y=cpl_image_get_size_y(cpl_imagelist_get(ilist,0));
826 detector_size=detector_size_x * detector_size_y * 0.0015 * 0.0015;
829 rate = rate/exptime*3600.0;
831 rate = rate/detector_size;
833 omega_darkcurrent_config.rate = rate;
870 cpl_propertylist *qclist, cpl_type_bpp bitpix,
871 const char *outfile, cpl_frame *product_frame)
875 const char *fctid =
"omega_darkcurrent_save";
876 cpl_propertylist *plist = NULL;
882 plist = cpl_propertylist_new();
885 if (cpl_dfs_setup_product_header(plist, product_frame, set, parlist,
886 RECIPE,PIPEID,DICID,NULL) != CPL_ERROR_NONE) {
888 cpl_msg_warning(fctid,
"Problem in the main header of product DFS-compliance") ;
894 cpl_propertylist_erase_regexp(plist,REM_PRIM_KEYS,0);
897 if (cpl_propertylist_save(plist,outfile,CPL_IO_DEFAULT) != CPL_ERROR_NONE){
898 cpl_msg_error(fctid,
"Cannot save product PHU");
904 cpl_frameset_insert(set,product_frame);
908 plist = cpl_propertylist_duplicate(ps.eh);
912 cpl_propertylist_append_int(plist,
"ESO DRS OVERSCAN METHOD", omega_darkcurrent_config.oc);
913 cpl_propertylist_set_comment(plist,
"ESO DRS OVERSCAN METHOD",
"overscan correction method");
916 if (cpl_dfs_setup_product_header(plist, product_frame, set, parlist,
917 RECIPE,PIPEID,DICID,NULL) != CPL_ERROR_NONE) {
919 cpl_msg_warning(fctid,
"Problem in the extension header of product DFS-compliance") ;
923 cpl_propertylist_erase_regexp(plist, REM_EXT_KEYS, 0);
927 cpl_propertylist_append(plist, qclist);
930 if (cpl_image_save(image,outfile,bitpix,plist,
931 CPL_IO_EXTEND) != CPL_ERROR_NONE) {
932 cpl_msg_error(fctid,
"Cannot save product. %s", cpl_error_get_message());
939 if(omega_darkcurrent_config.paf){
942 char *outpaf = cpl_sprintf(
"%s_%d.paf",prefix,xtnum);
943 const char pafcopy[] =
"^(DATE-OBS|ARCFILE|ESO TPL ID|ESO DET WIN1 DIT1|MJD-OBS|EXTNAME|ESO PRO CATG)$";
944 cpl_frame *fframe = cpl_frameset_get_position(set, 0) ;
945 cpl_propertylist *mlist = cpl_propertylist_load_regexp(cpl_frame_get_filename(fframe),0,pafcopy, 0);
946 cpl_propertylist_copy_property_regexp(qclist, mlist, pafcopy, 0);
947 if (cpl_propertylist_copy_property_regexp(qclist, plist,
948 pafcopy, 0) != CPL_ERROR_NONE){
950 cpl_msg_warning(fctid,
"Some mandatory keywords are missing in PAF file");
953 cpl_dfs_save_paf(INSTRUME, RECIPE, qclist, outpaf);
964 static void omega_darkcurrent_init(
void) {
974 static void omega_darkcurrent_tidy(
void) {
975 freespace(ps.labels);
976 freeframeset(ps.darklist);
978 freefits(ps.firstdark);
int omega_pfits_get_overscan(const cpl_frame *frame, int xn)
Get the DRS keyword of the overscan method used to reduce the image.
double omega_pfits_get_exptime(const cpl_propertylist *plist)
Get the EXPTIME value.
cpl_stats * omega_iter_stat(cpl_image *img, double threshold, int iter)
Compute statistics of an image iteratively.
int omega_pfits_get_detlive(const cpl_propertylist *plist, int *detlive)
Get the value of DET_LIVE.
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.
cpl_image * TrimOscanCorrect(const cpl_frame *frame, int oscan, int extn)
This method loads a raw image, trims it and (optionally) performs an overscan correction, using the statistics of the pre and overscan regions. This can be done with a single value for the whole image or on a per-row basis.
int omega_darkcurrent_combine(cpl_parameterlist *pars, int xn)
Trim and combine input images.
int omega_compare_tags(const cpl_frame *frame1, const cpl_frame *frame2)
omega_fits * omega_fits_load(const cpl_frame *inframe, cpl_type type, int extnum)
int omega_fits_get_extnum(omega_fits *p)
const char * omega_get_license(void)
Get the pipeline copyright and license.
void omega_exten_range(int inexten, int *out1, int *out2)
cpl_frame * omega_product_frame(const char *filename, const char *tag, cpl_frame_type type)
Setup a frame to save a product.
char * omega_get_root_name(const char *filename)
Find out the root part of a basename (name without extension).
cpl_propertylist * omega_fits_get_ehu(omega_fits *p)
cpl_frameset * omega_frameset_subgroup(cpl_frameset *frameset, cpl_size *labels, cpl_size nlab, const char *tag)
int omega_darkcurrent_save(cpl_image *image, cpl_frameset *set, cpl_parameterlist *parlist, cpl_propertylist *qclist, cpl_type_bpp bitpix, const char *outfile, cpl_frame *product_frame)
Save the omega_darkcurrent recipe products on disk.
int omega_save_image(const cpl_image *img, cpl_frameset *set, const cpl_parameterlist *pars, cpl_propertylist *alist, const cpl_propertylist *qclist, cpl_type_bpp bpp, const char *name, const char *recipe, cpl_frame *frame, const cpl_frame *inherit, int isfirst)
Save an image as a DFS compliant product.