/*---------------------------------------------------------------------------- File name : jitter_ini.c Author : N. Devillard Created on : Sept 30, 1997 Description : Jitter mode ini file handling for ISAAC/SOFI ---------------------------------------------------------------------------*/ /* $Id: jitter_ini.c,v 1.27 2002/01/17 10:39:52 ndevilla Exp $ $Author: ndevilla $ $Date: 2002/01/17 10:39:52 $ $Revision: 1.27 $ */ /*--------------------------------------------------------------------------- Includes ---------------------------------------------------------------------------*/ #include "jitter_ini.h" #include "jitter_offset.h" /*--------------------------------------------------------------------------- Functions private to this module ---------------------------------------------------------------------------*/ static void parse_section_general(dictionary*, jitter_config *, int*); static void parse_section_frames(dictionary*, jitter_config *, int*); static void parse_section_cosmetics(dictionary*, jitter_config *, int*); static void parse_section_sky(dictionary*, jitter_config *, int*); static void parse_section_saa(dictionary*, jitter_config *, int*); static void parse_section_postproc(dictionary*, jitter_config *, int*); static void parse_section_output(dictionary*, jitter_config *, int*); static void generate_output_section(FILE *, char *); static void generate_calibration_section(FILE *, char *); static void generate_input_section(FILE *, char *); static int jitter_extendedcheck(jitter_config * cfg); /*-------------------------------------------------------------------------*/ /** @name generate_ini_file @memo Generate a default ini file for the jitter command. @param ini_name Name of the file to generate. @param name_i Name of the input file. @param name_o Name of the output file. @param name_c Name of the calibration file. @return int 0 if Ok, -1 otherwise. @doc This function generates a default ini file for the jitter command. The generated file will have the requested name. If you do not want to provide names for the input/output/calib files, feed either NULL pointers or character strings starting with (char)0. */ /*--------------------------------------------------------------------------*/ int generate_ini_file( char * ini_name, char * name_i, char * name_o, char * name_c ) { FILE * ini_file ; if (file_exists(ini_name)) { e_warning("overwriting %s", ini_name) ; } if ((ini_file = fopen(ini_name, "w")) == (FILE*)NULL) { e_error("cannot create .ini file %s", ini_name) ; return 1 ; } fprintf(ini_file, "#\n" "# Configuration file for jitter imaging reduction\n" "# %s\n" "#\n", create_timestamp()); fprintf(ini_file, "#\n" "# Please check out the following pages regularly for updates:\n" "#\n" "# Infrared jitter imaging data reduction algorithms\n" "# http://www.eso.org/projects/dfs/papers/jitter99/\n" "#\n" "# Frequently Asked Questions about eclipse,\n" "# has a dedicated section for the 'jitter' command.\n" "# http://www.eso.org/eclipse/faq\n" "#\n" "# eclipse main WWW site:\n" "# http://www.eso.org/eclipse\n" "#\n" "# Please read the algorithmic manual BEFORE you start using\n" "# this software. Please!\n" "#\n"); fprintf(ini_file, "\n" "[General]\n" "Eclipse = %s ;\n" "ExtendedChecks = no ; activate extended input data checking\n" "\n" "\n", get_eclipse_version()) ; generate_input_section(ini_file, name_i); generate_calibration_section(ini_file, name_c); fprintf(ini_file, "#\n" "# -------------------- SKY SUBTRACTION\n" "#\n" "\n" "[SkyEngine]\n" "EstimateSky = yes ; activate sky estimation\n" "OutputDiff = no ; activate output (object - sky)\n" "\n"); fprintf(ini_file, "\n" "[SkyCombine]\n" "MinNumberOfFrames = 10 ; min # of frames to run sky estimation\n" "RejectHalfWidth = 7 ; rejection halfwidth (int)\n" "RejectMin = 3 ; rejection min (int)\n" "RejectMax = 3 ; rejection max (int)\n" "SeparateQuadrants = no ; separate quadrants for sky subtraction\n" "\n" "\n") ; fprintf(ini_file, "#\n" "# -------------------- SHIFT AND ADD\n" "#\n" "# Shift and add is separated into the following sections:\n" "# -> object acquisition (detection or file read)\n" "# -> offset detection/estimation\n" "# -> plane registration and stacking\n" "#\n"); fprintf(ini_file, "\n" "[ShiftAndAdd]\n" "Activate = yes ; activate shift and add\n" "\n" "# Identify source of cross-correlating objects: auto or file\n" "ObjectSource = auto ; auto/file\n" "\n"); fprintf(ini_file, "# Only valid if ObjectSource is 'auto'\n" "AutoDetectImage = diff ; diff/first\n" "AutoThreshold = 2.0 ; peak detection sigma threshold\n" "AutoMinPoints = 1 ; min # of peaks to detect\n" "AutoMaxPoints = 1 ; max # of peaks to detect\n" "AutoOutputObjects = no ; dump objects to separate file\n" "\n"); fprintf(ini_file, "# Only valid if ObjectSource is 'file'\n" "ObjectFileName = objects.in ; name of the input object file\n" "\n" "# Identify source of offsets between frames\n" "OffsetInput = header ; header/file/auto\n" "\n" "# The following is valid if Input=header\n" "# Leave it as 'isaac-default' for ISAAC data, or specify\n" "# a FITS keyword name for other data.\n" "OffsetXKeyword = isaac-default ;\n" "OffsetYKeyword = isaac-default ;\n" "\n"); fprintf(ini_file, "# The following is valid if Input=file\n" "OffsetInputFile = offsets.in\n" "\n" "# These parameters specify the cross-correlation search\n" "OffsetRefine = yes ; activate offset refining\n" "OffsetSearchSizeX = 10 ; search halfsize (int)\n" "OffsetSearchSizeY = 10 ; search halfsize (int)\n" "OffsetMeasureSizeX = 45 ; measure halfsize (int)\n" "OffsetMeasureSizeY = 45 ; measure halfsize (int)\n" "\n" "OffsetFileOutput = yes ; dump used offsets to separate file\n" "\n"); fprintf(ini_file, "# Frame averaging is done with a 3d filter rejection\n" "# Specify here the number of min and max pixels to reject\n" "AverageRejectMin = 3 ; Number of min pixels to reject in stacking\n" "AverageRejectMax = 3 ; Number of max pixels to reject in stacking\n" "\n" "\n") ; fprintf(ini_file, "#\n" "# -------------------- POST-PROCESSING\n" "#\n" "# RowSubtractMedian will compute the median pixel value for all\n" "# rows in the image and subtract this value from all pixels in the\n" "# row. It is a very efficient algorithm to remove saturation effects\n" "# and it does not affect \"normal\" lines.\n" "#\n"); fprintf(ini_file, "# ProduceStatusReport produces an ASCII file describing the status\n" "# of the algorithm at the end of the process. There is information\n" "# about how well each part of the algorithm performed, and all\n" "# possible intermediate information such as detected objects for\n" "# cross-correlation, the offsets which were used, sky background\n" "# measurements, etc.\n" "# The name of this report file is 'basename'_status.ascii, where\n" "# 'basename' is declared in the [Output]:Basename section.\n" "\n"); fprintf(ini_file, "[PostProcessing]\n" "Activate = yes ; if not set none of the following occurs\n" "RowSubtractMedian = yes ; to remove row saturation effects\n" "ProduceStatusReport = yes ; to produce global status report\n" "ProduceQCReport = yes ; to produce QC PAF file\n" "\n" "# Included as 'post-processing' is the ability to start\n" "# an image viewer to see the results when 'jitter' has\n" "# finished working. Specify the command-line to start it,\n" "# %%s being the name of the output file\n" "\n"); fprintf(ini_file, "StartViewer = no ; to launch a viewer when finished\n" "StartCommand = \"saoimage -fits %%s\" ;\n" "#\n" "# Examples:\n" "#\n" "# StartCommand = \"saoimage -fits %%s\" ;\n" "# StartCommand = \"rtd %%s\" ;\n" "# StartCommand = \"xv %%s\" ;\n" "#\n" "\n" "\n") ; generate_output_section(ini_file, name_o); fprintf(ini_file, "#\n" "# ----- end of file\n" "#\n") ; fclose(ini_file) ; return 0 ; } /*-------------------------------------------------------------------------*/ /** @name parse_jitter_ini_file @memo Parse a jitter.ini file and create a blackboard. @param ini_name Name of the ASCII file to parse. @return 1 newly allocated jitter blackboard structure. @doc The requested ini file is parsed and a blackboard object is created, then updated accordingly. Returns NULL in case of error. */ /*--------------------------------------------------------------------------*/ jitter_config * parse_jitter_ini_file(char * ini_name) { dictionary * sym ; jitter_config * cfg ; int status ; if (!file_exists(ini_name)) { e_error("cannot find ini file [%s]: aborting", ini_name) ; return NULL ; } sym = iniparser_load(ini_name) ; if (sym == NULL) { e_error("in parsing ini file [%s]: aborting", ini_name) ; return NULL ; } cfg = jitter_cfg_create(); if (cfg==NULL) { e_error("allocating jitter cfg struct"); iniparser_freedict(sym) ; return NULL ; } /* * Perform sanity checks, fill up the structure with what was * found in the ini file */ status = 0 ; parse_section_general (sym, cfg, &status); parse_section_frames (sym, cfg, &status); parse_section_cosmetics (sym, cfg, &status); parse_section_sky (sym, cfg, &status); parse_section_saa (sym, cfg, &status); parse_section_postproc (sym, cfg, &status); parse_section_output (sym, cfg, &status); iniparser_freedict(sym); if (status>0) { e_error("%d errors in ini file [%s]", status, ini_name); jitter_cfg_destroy(cfg); cfg = NULL ; return NULL ; } if (cfg->extended_check) { status = jitter_extendedcheck(cfg) ; if (status!=0) { e_error("%d error(s) found in input data", status); jitter_cfg_destroy(cfg); cfg = NULL ; } } return cfg ; } /*--------------------------------------------------------------------------- Functions: parse_section_???() In : symbolic table read from ini file Out : void Job : update a jitter_config structure from what can be found in the ini file. Notice : all of these functions update a status integer to indicate if an error occurred, or leave it as it is if everything went Ok. parse_section_general() parse_section_frames() parse_section_cosmetics() parse_section_sky() parse_section_saa() parse_section_postproc() parse_section_output() ---------------------------------------------------------------------------*/ static void parse_section_general( dictionary * sym, jitter_config * cfg, int *status ) { char * cval ; /* * General section: nothing mandatory there */ cval = iniparser_getstr(sym, "general:eclipse") ; if (cval!=NULL) { if (strcmp(cval, get_eclipse_version())) { e_warning("this ini file produced by version %s", cval); e_warning("you are running version %s", get_eclipse_version()); } } else { e_warning("no eclipse version number found in file"); } cfg->extended_check = iniparser_getboolean(sym, "general:extendedchecks", 0); return ; } static void parse_section_frames( dictionary * sym, jitter_config * cfg, int * status ) { char * listname ; charmatrix * charm ; int i, j ; char * name, * type ; int nval, nobj ; int found_sky ; char ** input_list ; int * frametypes ; listname = iniparser_getstr(sym, "frames:filelist"); if (is_ascii_list(listname)!=1) { e_error("file [%s] is not an ASCII list: aborting", listname); (*status)++ ; return ; } /* Read input char matrix */ charm = charmatrix_read(listname); if (charm==NULL) { e_error("parsing input list [%s]", listname); (*status)++; return ; } /* Check input matrix */ nval = charm->ly ; for (j=0 ; jly ; j++) { /* Check file existence */ name = charmatrix_elem(charm, 0, j); if (file_exists(name)!=1) { e_warning("file [%s] declared in list does not exist", name); nval -- ; } } if (nval<1) { e_error("no valid plane found in list [%s]", listname); charmatrix_del(charm); (*status)++ ; return ; } /* Allocate structures to go into the blackboard */ input_list = malloc(nval * sizeof(char*)); frametypes = malloc(nval * sizeof(int)); found_sky = 0 ; nobj = 0 ; /* Browse through the charmatrix to get names and file types */ i=0 ; for (j=0 ; jly ; j++) { name = charmatrix_elem(charm, 0, j); if (file_exists(name)==1) { /* Store file name into input_list */ input_list[i] = strdup(name); /* Check if a file type is present */ if (charm->lx>1) { /* Get file type */ type = strlwc(charmatrix_elem(charm, 1, j)); /* Checking if the type contains 'sky' */ if (strstr(type, "sky")!=NULL) { frametypes[i] = FRAME_SKY ; found_sky = 1 ; } else { frametypes[i] = FRAME_OBJ ; nobj++ ; } } else { /* No type means an object */ frametypes[i] = FRAME_OBJ ; nobj ++ ; } i++ ; } } charmatrix_del(charm); /* Copy relevant information into the blackboard */ strcpy(cfg->frames_filelist, listname); cfg->input_list = input_list ; cfg->frametype = frametypes ; cfg->nframes = nval ; cfg->nobj = nobj ; cfg->contains_sky = found_sky ; return ; } static void parse_section_cosmetics( dictionary * sym, jitter_config * cfg, int *status ) { char * cval ; cval = iniparser_getstr(sym, "calibrationdata:dark") ; if (cval!=NULL) { if (strcmp(cval, "none")) { if (file_exists(cval)!=1) { e_error("dark file [%s] does not exist", cval); (*status)++ ; } else { cfg->dark_subtraction = 1 ; strcpy(cfg->dark_filename, cval); } } } cval = iniparser_getstr(sym, "calibrationdata:flatfield") ; if (cval!=NULL) { if (strcmp(cval, "none")) { if (file_exists(cval)!=1) { e_error("flat-field file [%s] does not exist", cval); (*status)++ ; } else { cfg->flatfield_division = 1 ; strcpy(cfg->flatfield_filename, cval); } } } cval = iniparser_getstr(sym, "calibrationdata:badpixelmap") ; if (cval!=NULL) { if (strcmp(cval, "none")) { if (file_exists(cval)!=1) { e_error("bad pixel map [%s] does not exist", cval); (*status)++ ; } else { cfg->badpixels_replacement = 1 ; strcpy(cfg->badpixels_filename, cval); } } } return ; } static void parse_section_sky( dictionary * sym, jitter_config * cfg, int *status ) { /* Sky engine */ if (iniparser_getboolean(sym, "skyengine:estimatesky", 1)==0) { /* No sky removal requested */ cfg->sky_estimate = 0 ; return ; } /* Sky removal requested */ cfg->sky_estimate = 1; /* Output difference flag */ cfg->sky_outputdiff = iniparser_getboolean(sym, "skyengine:outputdiff",0); /* Sky combination parameters */ cfg->sky_minnumofframes = iniparser_getint(sym, "skycombine:minnumberofframes", 0) ; cfg->sky_rejhalfwidth = iniparser_getint(sym, "skycombine:rejecthalfwidth", 0); cfg->sky_rejmin = iniparser_getint(sym, "skycombine:rejectmin", 0); cfg->sky_rejmax = iniparser_getint(sym, "skycombine:rejectmax", 0); cfg->sky_sepquad = iniparser_getboolean(sym, "skycombine:separatequadrants", 0); if (cfg->sky_rejmin + cfg->sky_rejmax >= cfg->sky_rejhalfwidth) { e_error("in sky filter definition:"); e_error("rejection min(%d) + max(%d) >= halfwidth(%d)", cfg->sky_rejmin, cfg->sky_rejmax, cfg->sky_rejhalfwidth); (*status)++ ; } return ; } static void parse_section_saa( dictionary * sym, jitter_config * cfg, int *status ) { int ival ; double dval ; char * cval ; cfg->saa_apply = iniparser_getboolean(sym, "shiftandadd:activate", 1); if (cfg->saa_apply==0) { return ; } /* Source acquisition from? */ cval = iniparser_getstr(sym, "shiftandadd:objectsource") ; if (cval==NULL) { /* Nothing specified: switch to automatic */ e_warning("no source specified for object acquisition"); e_warning("switching to automatic"); cfg->saa_objacq_source = OBJACQ_AUTO ; } else { if (!strcmp(cval, "auto")) { /* Automatic mode */ cfg->saa_objacq_source = OBJACQ_AUTO ; } else if (!strcmp(cval, "file")) { /* User provided list of objects */ cfg->saa_objacq_source = OBJACQ_FILE ; } else { /* Invalid specified source */ e_error("invalid object source: [%s]", cval); e_error("in [ShiftAndAdd]:ObjectSource"); (*status)++ ; return ; } } switch (cfg->saa_objacq_source) { case OBJACQ_AUTO: /* get DetectImage */ cval = iniparser_getstr(sym, "shiftandadd:autodetectimage"); if (cval==NULL) { /* No detect image specified: exit */ e_error("in [ShiftAndAdd]:AutoDetectImage"); e_error("automatic object finder activated"); e_error("but no detect image was specified"); (*status)++; return ; } if (!strcmp(cval, "diff")) { /* Detect image is first difference */ cfg->saa_autodetectimage = DETIM_DIFF ; } else if (!strcmp(cval, "first")) { /* Detect image is first frame in stack */ cfg->saa_autodetectimage = DETIM_FIRST ; } else { /* Invalid specified detect image: exit */ e_error("in [ShiftAndAdd]:AutoDetectImage"); e_error("invalid specification [%s]", cval); e_error("should be 'first' or 'diff'"); (*status)++; return ; } /* get DetectThreshold */ dval = iniparser_getdouble(sym, "shiftandadd:autothreshold", -1.0); if (dval<0.0) { /* Invalid threshold: exit */ e_error("[ShiftAndAdd]:AutoThreshold is missing or invalid"); (*status)++ ; return ; } cfg->saa_autothreshold = dval ; /* get min and max detect points */ cfg->saa_autominpts = iniparser_getint(sym, "shiftandadd:autominpoints", -1); if (cfg->saa_autominpts<0) { e_warning("illegal or no value for [ShiftAndAdd]:AutoMinPoints"); e_warning("using AutoMinPoints=1"); cfg->saa_autominpts = 1 ; } cfg->saa_automaxpts = iniparser_getint(sym, "shiftandadd:automaxpoints", -1); if (cfg->saa_automaxpts<0) { e_warning("illegal or no value for [ShiftAndAdd]:AutoMaxPoints"); e_warning("using AutoMaxPoints=1"); cfg->saa_automaxpts = 1 ; } if (cfg->saa_automaxptssaa_autominpts) { e_error("AutoMinPoints (%d) > AutoMaxPoints (%d)", cfg->saa_autominpts, cfg->saa_automaxpts); (*status)++ ; } /* Need to output objects to separate file? */ cfg->saa_outputobjs = iniparser_getboolean(sym, "shiftandadd:autooutputobjects", 0); break ; case OBJACQ_FILE: /* Find out file name to read objects from */ cval = iniparser_getstr(sym, "shiftandadd:objectfilename"); if (cval==NULL) { e_error("[ShiftAndAdd]:ObjectFileName does not exist"); e_error("user-defined list of objects requested"); e_error("but no input file was specified"); (*status)++ ; return ; } if (file_exists(cval)!=1) { e_error("in [ShiftAndAdd]:ObjectFileName"); e_error("file [%s] does not exist", cval); (*status)++ ; } strcpy(cfg->saa_objacq_filename, cval); break ; } /* Offset section */ /* Retrieve offset source */ cval = iniparser_getstr(sym, "shiftandadd:offsetinput") ; if (cval==NULL) { e_error("specify a value for [ShiftAndAdd]:OffsetInput"); (*status)++ ; return ; } if (!strcmp(cval, "header")) { cfg->saa_offinput = OFFSIN_HEADER ; } else if (!strcmp(cval, "file")) { cfg->saa_offinput = OFFSIN_FILE ; } else if (!strcmp(cval, "auto")) { cfg->saa_offinput = OFFSIN_AUTO ; } else { e_error("[ShiftAndAdd]:OffsetInput has illegal value [%s]", cval); e_error("should be 'header', 'file' or 'auto'"); (*status)++; return ; } /* For header offsets, get the associated keywords */ if (cfg->saa_offinput == OFFSIN_HEADER) { /* Get X offset keyword */ cval = iniparser_getstr(sym, "shiftandadd:offsetxkeyword"); if (cval==NULL) { e_error("[ShiftAndAdd]:OffsetInput specifies header offsets"); e_error("but cannot find [ShiftAndAdd]:OffsetXKeyword"); (*status)++ ; return ; } strcpy(cfg->saa_off_xkey, cval); /* Get Y offset keyword */ cval = iniparser_getstr(sym, "shiftandadd:offsetykeyword"); if (cval==NULL) { e_error("[ShiftAndAdd]:OffsetInput specifies header offsets"); e_error("but cannot find [ShiftAndAdd]:OffsetYKeyword"); (*status)++ ; return ; } strcpy(cfg->saa_off_ykey, cval); } /* For file offsets, get the associated file name */ if (cfg->saa_offinput == OFFSIN_FILE) { cval = iniparser_getstr(sym, "shiftandadd:offsetinputfile"); if (cval==NULL) { e_error("[ShiftAndAdd]:OffsetInput specifies File offsets"); e_error("but cannot find [ShiftAndAdd]:OffsetInputFile"); (*status)++ ; return ; } strcpy(cfg->saa_off_filename, cval); } /* Get refine flag and possibly search parameters */ cfg->saa_off_refine = iniparser_getboolean(sym,"shiftandadd:offsetrefine", 0) ; if (cfg->saa_off_refine) { /* Get search size in X */ ival = iniparser_getint(sym,"shiftandadd:offsetsearchsizex",-1); if (ival<0) { e_error("missing [ShiftAndAdd]:OffsetSearchSizeX"); (*status)++; } cfg->saa_off_sx = ival ; /* Get search size in Y */ ival = iniparser_getint(sym,"shiftandadd:offsetsearchsizey",-1); if (ival<0) { e_error("missing [ShiftAndAdd]:OffsetSearchSizeY"); (*status)++; } cfg->saa_off_sy = ival ; /* Get measure size in X */ ival = iniparser_getint(sym,"shiftandadd:offsetmeasuresizex",-1); if (ival<0) { e_error("missing [ShiftAndAdd]:OffsetMeasureSizeX"); (*status)++; } cfg->saa_off_hx = ival ; /* Get measure size in Y */ ival = iniparser_getint(sym,"shiftandadd:offsetmeasuresizey",-1); if (ival<0) { e_error("missing [ShiftAndAdd]:OffsetMeasureSizeY"); (*status)++; } cfg->saa_off_hy = ival ; } /* Need to output used offsets to separate file? */ cfg->saa_offoutput = iniparser_getboolean(sym, "shiftandadd:offsetfileoutput", 0); /* 3d average */ cfg->saa_filt_lo = iniparser_getint(sym, "shiftandadd:averagerejectmin", -1); if (cfg->saa_filt_lo<0) { e_error("missing [ShiftAndAdd]:AverageRejectMin"); (*status)++; } cfg->saa_filt_hi = iniparser_getint(sym, "shiftandadd:averagerejectmax", -1); if (cfg->saa_filt_hi<0) { e_error("missing [ShiftAndAdd]:AverageRejectMax"); (*status)++; } return ; } static void parse_section_postproc( dictionary * sym, jitter_config * cfg, int *status ) { char * cval ; /* Post processing section is optional */ if (iniparser_getboolean(sym, "postprocessing:activate", 0)==0) { /* Inactive */ cfg->postproc_active = 0 ; return ; } /* Active: get all parameters */ cfg->postproc_active = 1 ; if (iniparser_getboolean(sym,"postprocessing:rowsubtractmedian", 1)==1) { cfg->postproc_rowmediansub = 1 ; } if (iniparser_getboolean(sym,"postprocessing:startviewer",0)==1) { cfg->postproc_startviewer = 1 ; cval = iniparser_getstr(sym, "postprocessing:startcommand") ; if (cval == NULL) { e_error("viewer start requested but no viewer provided"); cfg->postproc_startviewer = 0 ; (*status)++ ; } else { strcpy(cfg->postproc_viewer, cval); } } /* Produce final status report? */ if (iniparser_getboolean(sym,"postprocessing:producestatusreport",1)==1) { cfg->postproc_statusreport = 1 ; } /* Produce final QC report? */ if (iniparser_getboolean(sym,"postprocessing:produceqcreport",1)==1) { cfg->postproc_qcreport = 1 ; } return ; } static void parse_section_output( dictionary * sym, jitter_config * cfg, int *status ) { char * cval ; /* Output section is optional, cannot trigger errors */ cval = iniparser_getstr(sym, "output:basename") ; if (cval==NULL) { e_warning("default output base name used: [jittered_result]"); strcpy(cfg->output_basename, "jittered_result"); } else { strcpy(cfg->output_basename, cval); } return ; } /*--------------------------------------------------------------------------- Function : generate_output_section() In : opened ini file for output, optional name of the output file Out : to the ini file: section about base name of output file Job : print out the [Output]:Basename section Notice : provide either a NULL string or a character string starting with (char)0 if you do not have a default ---------------------------------------------------------------------------*/ static void generate_output_section(FILE * ini_file, char * name_o) { fprintf(ini_file, "#\n" "# -------------------- SAVING THE OUTPUT\n" "#\n" "# All files created by 'jitter' will be named according to the\n" "# following convention: basename_[type].[extension]\n" "# where basename is declared in the following section,\n" "# [type] depends on the frame type\n" "# and [extension] depends on the file format (fits, tfits, or paf)\n" "#\n" "\n" "[Output]\n" "BaseName = " "%s ;\n\n\n", name_o); return ; } /*--------------------------------------------------------------------------- Function : generate_calibration_section() In : opened ini file for output, optional name of the calib file Out : to the ini file: section about calibration files Job : print out the calibration section Notice : provide either a NULL string or a character string starting with (char)0 if you do not have a default ---------------------------------------------------------------------------*/ static void generate_calibration_section(FILE * ini_file, char * name_c) { /* Input calibration file name is ignored for the moment */ fprintf(ini_file, "#\n" "# -------------------- DARK/FLAT-FIELD/BAD PIXELS\n" "#\n" "# Dark subtraction, flat-field division and bad pixel replacement\n" "# can be activated here. Provide a file name containing the correct\n" "# calibration data in each case.\n" "# If you do not provide these files, specify 'none' as filename\n" "#\n" "\n" "[CalibrationData]\n" "Dark = none ; name of the dark file\n" "FlatField = none ; name of the flatfield file\n" "BadPixelMap = none ; name of a bad pixel map\n" "\n"); return ; } /*--------------------------------------------------------------------------- Function : generate_input_section() In : opened ini file for output, optional name of the input file Out : to the ini file: section about input files Job : print out the Input section Notice : provide either a NULL string or a character string starting with (char)0 if you do not have a default ---------------------------------------------------------------------------*/ static void generate_input_section(FILE * ini_file, char * name_i) { fprintf(ini_file, "#\n" "# -------------------- INPUT FILES\n" "#\n" "# Input file names are stored in a separate file.\n" "# The input frame list is an ASCII file containing\n" "# the file name in first column and the frame type\n" "# in second column. The frame type is indicating if\n" "# the frame is an object or a sky.\n" "#\n"); fprintf(ini_file, "# Actually, if the string in second column contains\n" "# anywhere the string 'sky' (case insensitive) then\n" "# the frame is taken as a sky, otherwise as an object.\n" "#\n" "# Example:\n" "# file1 object\n" "# file2 sky\n" "# file3 object\n" "# file4 sky\n" "#\n"); fprintf(ini_file, "# is similar to:\n" "# file1\n" "# file2 SKY_FRAME\n" "# file3 this is an object frame\n" "# file4 sky\n" "#\n"); fprintf(ini_file, "# Frame names in the input file are expected in\n" "# same order as they were generated, one file name\n" "# per line, no comments allowed.\n" "#\n" "#\n" "\n" "[Frames]\n" "FileList = %s ; contains the list of frames to process\n\n\n", name_i); return ; } /*-------------------------------------------------------------------------*/ /** @name jitter_extendedcheck @memo Extended configuration checks. @param cfg Jitter blackboard @return int 0 if everything Ok, positive integer otherwise. @doc This function performs a number of extended checks on the requested reduction. It goes as far as looking into all data sources to see if they are consistent. It returns an integer specifying the number of errors/inconsistencies which occurred during the check. */ /*--------------------------------------------------------------------------*/ static int jitter_extendedcheck(jitter_config * cfg) { image_t * img ; pixelmap * map ; int errors ; int s_last[2] ; int s_first[2] ; int i ; double3 * d ; int ed_x, ed_y ; /* Section by section, check that all data are loadable */ errors = 0 ; /* * Input framelist */ e_comment(1, "checking input list..."); s_first[0] = s_first[1] = -1 ; for (i=0 ; inframes ; i++) { compute_status("checking input frames...", i, cfg->nframes, 1); img = image_load(cfg->input_list[i]); if (img==NULL) { e_error("cannot load frame [%s]", cfg->input_list[i]); errors++ ; } else { if (s_first[0]<0 || s_first[1]<0) { s_first[0] = img->lx ; s_first[1] = img->ly ; } else { if ((img->lx!=s_first[0]) || (img->lx!=s_first[1])) { e_error("inconsistent image size in frame[%s]", cfg->input_list[i]); errors++ ; } } image_del(img); } } /* * Dark, flat-field, bad pixel map */ if (cfg->dark_subtraction) { e_comment(1, "checking dark..."); img = image_load(cfg->dark_filename); if (img==NULL) { e_error("cannot load dark: [%s]", cfg->dark_filename); errors++; } else { s_last[0] = img->lx ; s_last[1] = img->ly ; image_del(img); if ((s_last[0]!=s_first[0]) || (s_last[1]!=s_first[1])) { e_error("dark frame size inconsistent with data set"); e_error("frame [%s] is [%dx%d]", cfg->input_list[0], s_first[0], s_first[1]); e_error("dark [%s] is [%dx%d]", cfg->dark_filename, s_last[0], s_last[1]); errors++ ; } } } if (cfg->flatfield_division) { e_comment(1, "checking flat-field..."); img = image_load(cfg->flatfield_filename); if (img==NULL) { e_error("cannot load flat-field: [%s]", cfg->flatfield_filename); errors++; } else { s_last[0] = img->lx ; s_last[1] = img->ly ; image_del(img); if ((s_last[0]!=s_first[0]) || (s_last[1]!=s_first[1])) { e_error("flat-field frame size inconsistent with data set"); e_error("frame [%s] is [%dx%d]", cfg->input_list[0], s_first[0], s_first[1]); e_error("flat [%s] is [%dx%d]", cfg->flatfield_filename, s_last[0], s_last[1]); errors++ ; } } } if (cfg->badpixels_replacement) { e_comment(1, "checking bad pixel map..."); map = pixelmap_load(cfg->badpixels_filename); if (map==NULL) { e_error("cannot load bad pixel map: [%s]", cfg->badpixels_filename); errors++; } else { s_last[0] = map->lx ; s_last[1] = map->ly ; pixelmap_del(map); if ((s_last[0]!=s_first[0]) || (s_last[1]!=s_first[1])) { e_error("bad pixel map frame size inconsistent with data set"); e_error("frame [%s] is [%dx%d]", cfg->input_list[0], s_first[0], s_first[1]); e_error("map [%s] is [%dx%d]", cfg->badpixels_filename, s_last[0], s_last[1]); errors++ ; } } } /* * Sky engine */ if ((cfg->sky_rejmin+cfg->sky_rejmax) >= cfg->nframes) { e_error("in sky rejection parameters"); e_error("rejection minmax is [%d-%d]", cfg->sky_rejmin, cfg->sky_rejmax); e_error("input number of frames is %d", cfg->nframes); errors++; } /* * Shift and add */ /* Check that object list can be acquired and makes sense */ if (cfg->saa_objacq_source==OBJACQ_FILE) { e_comment(1, "checking input objects..."); /* Try acquiring the objects */ d = double3_read(cfg->saa_objacq_filename) ; if (d==NULL) { e_error("cannot read object list from [%s]", cfg->saa_objacq_filename) ; errors++ ; } else { for (i=0 ; in ; i++) { if ((d->x[i]<1) || (d->x[i]>s_first[0]) || (d->y[i]<1) || (d->y[i]>s_first[1])) { e_error("object [%d] is out of reach at [%d %d]", i, d->x[i], d->y[i]); errors++ ; } } double3_del(d); } } /* Check that detect image is correct */ e_comment(1, "checking input image..."); if ((cfg->saa_autodetectimage==DETIM_DIFF) && (cfg->sky_estimate == 0)) { e_error("detection image set to 'diff'"); e_error("probably invalid without sky estimation"); errors++ ; } /* Check that input offset list can indeed be loaded */ e_comment(1, "checking input offset loading..."); switch (cfg->saa_offinput) { case OFFSIN_HEADER: d = get_offsets_from_fits_header(cfg); if (d==NULL) { e_error("getting offsets from FITS header"); errors++ ; } break ; case OFFSIN_FILE: d = load_offsets_from_txtfile(cfg->saa_off_filename); if (d==NULL) { e_error("getting offsets from file [%s]"); errors++ ; } break ; case OFFSIN_AUTO: default: d = NULL ; break ; } ed_x = cfg->saa_off_sx + cfg->saa_off_hx ; ed_y = cfg->saa_off_sy + cfg->saa_off_hy ; /* Check that offsets are within reasonable range */ if (d!=NULL) { e_comment(1, "checking input offset range..."); if (d->n < cfg->nobj) { e_error("not enough provided offsets"); e_error("expected at least %d but got %d", cfg->nobj, d->n); errors++ ; } else { for (i=0 ; in ; i++) { if ((fabs(d->x[i])>s_first[0]) || (fabs(d->y[i])>s_first[1])) { e_error("provided offset out of range: [%g %g]", d->x[i], d->y[i]); errors++; } } } double3_del(d); } /* Check that search+measure size is correct */ e_comment(1, "checking cross-correlation setup..."); if ((ed_x > (s_first[0]/2)) || (ed_y > (s_first[1]/2))) { e_error("search + measure size is bigger than reference image"); e_error("ref image size is [%dx%d]", s_first[0], s_first[1]); e_error("search + measure size is [%dx%d]", ed_x, ed_y); errors++; } /* Check that rejection parameters are a priori correct */ e_comment(1, "checking 3d stack setup..."); if (cfg->nframes <= (cfg->saa_filt_lo + cfg->saa_filt_hi)) { e_error("in [ShiftAndAdd]: rejection parameters are too high"); e_error("AverageRejectMin set to %d", cfg->saa_filt_lo); e_error("AverageRejectMax set to %d", cfg->saa_filt_hi); e_error("only %d frames in input", cfg->nframes); errors++ ; } return errors; }