"Fossies" - the Fresh Open Source Software Archive

Member "gnuastro-0.8/bin/crop/ui.c" (27 Dec 2018, 36719 Bytes) of package /linux/privat/gnuastro-0.8.tar.lz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ui.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.7_vs_0.8.

    1 /*********************************************************************
    2 Crop - Crop a given size from one or multiple images.
    3 Crop is part of GNU Astronomy Utilities (Gnuastro) package.
    4 
    5 Original author:
    6      Mohammad Akhlaghi <mohammad@akhlaghi.org>
    7 Contributing author(s):
    8 Copyright (C) 2016-2018, Free Software Foundation, Inc.
    9 
   10 Gnuastro is free software: you can redistribute it and/or modify it
   11 under the terms of the GNU General Public License as published by the
   12 Free Software Foundation, either version 3 of the License, or (at your
   13 option) any later version.
   14 
   15 Gnuastro is distributed in the hope that it will be useful, but
   16 WITHOUT ANY WARRANTY; without even the implied warranty of
   17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   18 General Public License for more details.
   19 
   20 You should have received a copy of the GNU General Public License
   21 along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
   22 **********************************************************************/
   23 #include <config.h>
   24 
   25 #include <argp.h>
   26 #include <errno.h>
   27 #include <error.h>
   28 #include <stdio.h>
   29 #include <string.h>
   30 
   31 #include <gnuastro/wcs.h>
   32 #include <gnuastro/list.h>
   33 #include <gnuastro/fits.h>
   34 #include <gnuastro/blank.h>
   35 #include <gnuastro/table.h>
   36 #include <gnuastro/pointer.h>
   37 #include <gnuastro/dimension.h>
   38 
   39 #include <gnuastro-internal/timing.h>
   40 #include <gnuastro-internal/options.h>
   41 #include <gnuastro-internal/checkset.h>
   42 #include <gnuastro-internal/tableintern.h>
   43 #include <gnuastro-internal/fixedstringmacros.h>
   44 
   45 #include "main.h"
   46 
   47 #include "ui.h"
   48 #include "onecrop.h"
   49 #include "wcsmode.h"
   50 #include "authors-cite.h"
   51 
   52 
   53 
   54 
   55 
   56 /**************************************************************/
   57 /*********      Argp necessary global entities     ************/
   58 /**************************************************************/
   59 /* Definition parameters for the Argp: */
   60 const char *
   61 argp_program_version = PROGRAM_STRING "\n"
   62                        GAL_STRINGS_COPYRIGHT
   63                        "\n\nWritten/developed by "PROGRAM_AUTHORS;
   64 
   65 const char *
   66 argp_program_bug_address = PACKAGE_BUGREPORT;
   67 
   68 static char
   69 args_doc[] = "[Crop-identifiers] ASTRdata ...";
   70 
   71 const char
   72 doc[] = GAL_STRINGS_TOP_HELP_INFO PROGRAM_NAME" will create cutouts, "
   73   "thumbnails, postage stamps or crops of region(s) from input image(s) "
   74   "using image or celestial coordinates. If muliple crops are desired, a "
   75   "catalog must be provided. When in WCS mode, if the cut out covers more "
   76   "than one input image, all overlapping input images will be stitched in "
   77   "the output.\n"
   78   GAL_STRINGS_MORE_HELP_INFO
   79   /* After the list of options: */
   80   "\v"
   81   PACKAGE_NAME" home page: "PACKAGE_URL;
   82 
   83 
   84 
   85 
   86 
   87 
   88 
   89 
   90 
   91 
   92 
   93 
   94 
   95 
   96 
   97 
   98 
   99 
  100 
  101 
  102 /**************************************************************/
  103 /*********    Initialize & Parse command-line    **************/
  104 /**************************************************************/
  105 static void
  106 ui_initialize_options(struct cropparams *p,
  107                       struct argp_option *program_options,
  108                       struct argp_option *gal_commonopts_options)
  109 {
  110   size_t i;
  111   struct gal_options_common_params *cp=&p->cp;
  112 
  113 
  114   /* Set the necessary common parameters structure. */
  115   cp->program_name       = PROGRAM_NAME;
  116   cp->program_exec       = PROGRAM_EXEC;
  117   cp->program_bibtex     = PROGRAM_BIBTEX;
  118   cp->program_authors    = PROGRAM_AUTHORS;
  119   cp->poptions           = program_options;
  120   cp->numthreads         = gal_threads_number();
  121   cp->coptions           = gal_commonopts_options;
  122 
  123 
  124   /* Initalize necessary parameters. */
  125   p->mode         = IMGCROP_MODE_INVALID;
  126   cp->searchin    = GAL_TABLE_SEARCH_INVALID;
  127 
  128 
  129   /* Modify common options. */
  130   for(i=0; !gal_options_is_last(&cp->coptions[i]); ++i)
  131     {
  132       /* Select individually */
  133       switch(cp->coptions[i].key)
  134         {
  135         case GAL_OPTIONS_KEY_HDU:
  136           cp->coptions[i].mandatory=GAL_OPTIONS_MANDATORY;
  137           cp->coptions[i].doc="Extension name or number of (all) input(s).";
  138           break;
  139 
  140         case GAL_OPTIONS_KEY_MINMAPSIZE:
  141           cp->coptions[i].mandatory=GAL_OPTIONS_MANDATORY;
  142           break;
  143 
  144         case GAL_OPTIONS_KEY_SEARCHIN:
  145         case GAL_OPTIONS_KEY_IGNORECASE:
  146           cp->coptions[i].group=UI_GROUP_CENTER_CATALOG;
  147           break;
  148 
  149         case GAL_OPTIONS_KEY_STDINTIMEOUT:
  150           cp->coptions[i].group=OPTION_HIDDEN;
  151           break;
  152         }
  153 
  154       /* Select by group. */
  155       switch(cp->coptions[i].group)
  156         {
  157         case GAL_OPTIONS_GROUP_TESSELLATION:
  158           cp->coptions[i].doc=NULL; /* Necessary to remove title. */
  159           cp->coptions[i].flags=OPTION_HIDDEN;
  160           break;
  161         }
  162     }
  163 }
  164 
  165 
  166 
  167 
  168 
  169 /* Parse a single option: */
  170 error_t
  171 parse_opt(int key, char *arg, struct argp_state *state)
  172 {
  173   struct cropparams *p = state->input;
  174 
  175   /* Pass `gal_options_common_params' into the child parser.  */
  176   state->child_inputs[0] = &p->cp;
  177 
  178   /* In case the user incorrectly uses the equal sign (for example
  179      with a short format or with space in the long format, then `arg`
  180      start with (if the short version was called) or be (if the long
  181      version was called with a space) the equal sign. So, here we
  182      check if the first character of arg is the equal sign, then the
  183      user is warned and the program is stopped: */
  184   if(arg && arg[0]=='=')
  185     argp_error(state, "incorrect use of the equal sign (`=`). For short "
  186                "options, `=` should not be used and for long options, "
  187                "there should be no space between the option, equal sign "
  188                "and value");
  189 
  190   /* Set the key to this option. */
  191   switch(key)
  192     {
  193 
  194     /* Read the non-option tokens (arguments): */
  195     case ARGP_KEY_ARG:
  196       gal_list_str_add(&p->inputs, arg, 0);
  197       ++p->numin;
  198       break;
  199 
  200 
  201     /* This is an option, set its value. */
  202     default:
  203       return gal_options_set_from_key(key, arg, p->cp.poptions, &p->cp);
  204     }
  205 
  206   return 0;
  207 }
  208 
  209 
  210 
  211 
  212 /* Parse the mode to interpret the given coordinates. */
  213 void *
  214 ui_parse_coordinate_mode(struct argp_option *option, char *arg,
  215                          char *filename, size_t lineno, void *junk)
  216 {
  217   char *outstr;
  218 
  219   /* We want to print the stored values. */
  220   if(lineno==-1)
  221     {
  222       gal_checkset_allocate_copy( *(int *)(option->value)==IMGCROP_MODE_IMG
  223                                   ? "img" : "wcs", &outstr );
  224       return outstr;
  225     }
  226   else
  227     {
  228       if      (!strcmp(arg, "img")) *(int *)(option->value)=IMGCROP_MODE_IMG;
  229       else if (!strcmp(arg, "wcs")) *(int *)(option->value)=IMGCROP_MODE_WCS;
  230       else
  231         error_at_line(EXIT_FAILURE, 0, filename, lineno, "`%s' (value to "
  232                       "`--mode') not recognized as an input mode. "
  233                       "Recognized values are `img' and `wcs'. This option "
  234                       "is necessary to identify the nature of your input "
  235                       "coordinates.\n\n"
  236                       "Please run the following command for more "
  237                       "information (press the `SPACE' key to go down and "
  238                       "`q' to return to the command-line):\n\n"
  239                       "    $ info gnuastro \"Crop modes\"\n", arg);
  240       return NULL;
  241     }
  242 }
  243 
  244 
  245 
  246 
  247 
  248 
  249 
  250 
  251 
  252 
  253 
  254 
  255 
  256 
  257 
  258 
  259 
  260 
  261 
  262 
  263 /**************************************************************/
  264 /***************       Sanity Check         *******************/
  265 /**************************************************************/
  266 /* Read and check ONLY the options. When arguments are involved, do the
  267    check in `ui_check_options_and_arguments'. */
  268 static void
  269 ui_read_check_only_options(struct cropparams *p)
  270 {
  271   double *darray;
  272   int i, checksum;
  273 
  274   /* Make sure that only one of the crop definitions is given. */
  275   checksum = ( (p->center!=NULL)
  276                + (p->catname!=NULL)
  277                + (p->section!=NULL)
  278                + (p->polygon!=NULL) );
  279   switch(checksum)
  280     {
  281     case 0:
  282       error(EXIT_FAILURE, 0, "no crop definition. You can use any of the "
  283             "following options to define the crop(s): `--center', "
  284             "`--catalog', `--section', or `--polygon'. Please run this "
  285             "command for more information:\n\n"
  286             "    $ info gnuastro \"Crop modes\"\n");
  287     case 1:
  288       /* Everything is ok, just ignore the switch structure. */
  289       break;
  290     default:
  291       error(EXIT_FAILURE, 0, "more than one crop type specified. In each "
  292             "run, only one crop definition is acceptable on the "
  293             "command-line or in configuration files. You have called: "
  294             "%s%s%s%s\b\b.",
  295             p->center!=NULL  ? "`--center', " : "",
  296             p->catname!=NULL ? "`--catalog', " : "",
  297             p->section!=NULL ? "`--section', " : "",
  298             p->polygon!=NULL ? "`--polygon', " : "");
  299     }
  300 
  301 
  302   /* The width values must not be negative. */
  303   if(p->width)
  304     {
  305       darray=p->width->array;
  306       for(i=0;i<p->width->size;++i)
  307         if(darray[i]<=0.0f)
  308           error(EXIT_FAILURE, 0, "%g is <=0. The values to the `--width' "
  309                 "option must be larger than zero. %g is input number %d to "
  310                 "this option", darray[i], darray[i], i+1);
  311     }
  312 
  313 
  314   /* Checkcenter sanity check. */
  315   if(p->incheckcenter)
  316     {
  317       /* We only want a single number. */
  318       if(p->incheckcenter->size>1)
  319         error(EXIT_FAILURE, 0, "%zu values given to `--checkcenter'. This "
  320               "option only takes one value currently",
  321               p->incheckcenter->size);
  322 
  323       darray=p->incheckcenter->array;
  324       if(*darray<0.0f)
  325         error(EXIT_FAILURE, 0, "negative value (%f) given to "
  326               "`--checkcenter'. This option only takes positive values",
  327               *darray);
  328     }
  329 
  330 
  331   /* Section is currently only defined in Image mode. */
  332   if(p->section && p->mode!=IMGCROP_MODE_IMG)
  333     error(EXIT_FAILURE, 0, "The `--section' option is only available in "
  334           "image coordinate mode, currently it doesn't work with WCS mode. "
  335           "Please run with `--mode=img' and if necessary, change the "
  336           "values accordingly");
  337 
  338 
  339   /* Sanity checks and mode setting based on the desired crop. */
  340   if(p->catname)
  341     {
  342       /* If the searchin option has been given. */
  343       if(p->cp.searchin==GAL_TABLE_SEARCH_INVALID)
  344         error(EXIT_FAILURE, 0, "%s: no field specified to search for "
  345               "columns. Please use the `--searchin' option to specify "
  346               "which column meta-data you would like to search in: `name', "
  347               "`unit' and `comment'. You may also select columns by their "
  348               "number, which won't use this option, but for complentess its "
  349               "best for this option to have a value", p->catname);
  350 
  351       /* If it is a FITS file, we need the HDU. */
  352       if( gal_fits_name_is_fits(p->catname) && p->cathdu==NULL )
  353         error(EXIT_FAILURE, 0, "%s: no hdu given. Please use the `--cathdu' "
  354               "option to specify which extension contains the table",
  355               p->catname);
  356 
  357       /* Atleast one of the (X,Y), and (RA,Dec) set of columns are
  358          necessary. Note that we have checked that they are together if
  359          given, so we only need to check one of the two in each couple. */
  360       if(p->coordcol==NULL)
  361         error(EXIT_FAILURE, 0, "no crop center columns given to read from "
  362               "the input catalog (`%s'). Please use `--coordcol' two times "
  363               "to specify the column keeping the center position the "
  364               "respective dimension.\n\n"
  365               "For more information on how to select columns in Gnuastro, "
  366               "please run the following command:\n\n"
  367               "    $ info gnuastro \"Selecting table columns\"", p->catname);
  368     }
  369 
  370 
  371   /* Parse the polygon vertices if they are given to make sure that it is
  372      in the proper format. */
  373   if(p->polygon)
  374     {
  375       onecrop_parse_polygon(p);
  376       if(p->nvertices<3)
  377         error(EXIT_FAILURE, 0, "a polygon has to have 3 or more vertices, "
  378               "you have only given %zu (%s)", p->nvertices, p->polygon);
  379       if(p->outpolygon && p->numin>1)
  380         error(EXIT_FAILURE, 0, "currently in WCS mode, outpolygon can only "
  381               "be set to zero when there is one image, you have given %zu "
  382               "images. For multiple images the region will be very large. "
  383               "It is best if you first crop out the larger region you want "
  384               "into one image, then mask the polygon", p->numin);
  385     }
  386   else
  387     p->wpolygon=p->ipolygon=NULL;
  388 
  389 
  390   /* If we are in WCS mode, noblanks must be off */
  391   if(p->mode==IMGCROP_MODE_WCS && p->noblank)
  392     error(EXIT_FAILURE, 0, "`--noblanks` (`-b`) is only for image mode. "
  393           "You have called it with WCS mode");
  394 }
  395 
  396 
  397 
  398 
  399 
  400 static void
  401 ui_check_options_and_arguments(struct cropparams *p)
  402 {
  403   /* Make sure we actually have inputs. */
  404   if(p->inputs==NULL)
  405     error(EXIT_FAILURE, 0, "no input file given");
  406 
  407   /* Make sure that a HDU is also given. */
  408   if(p->cp.hdu==NULL )
  409     error(EXIT_FAILURE, 0, "no HDU specified. When the input is a FITS "
  410           "file, a HDU must also be specified, you can use the `--hdu' "
  411           "(`-h') option and give it the HDU number (starting from "
  412           "zero), extension name, or anything acceptable by CFITSIO");
  413 
  414   /* If in image mode, there should only be one input image. */
  415   if(p->mode==IMGCROP_MODE_IMG && p->numin>1)
  416     error(EXIT_FAILURE, 0, "in image mode, only one input image may be "
  417           "specified");
  418 
  419   /* If no output name is given, set it to the current directory. */
  420   if(p->cp.output==NULL)
  421     gal_checkset_allocate_copy("./", &p->cp.output);
  422 
  423   /* Only catalog mode needs multiple threads and a directory for the
  424      output. */
  425   if(p->catname)
  426     {
  427       /* When multiple threads need to access a file, CFITSIO needs to be
  428          configured with the `--enable-reentrant` option and we can only
  429          know from the `fits_is_reentrant' function that came from CFITSIO
  430          version 3.30. */
  431 #if GAL_CONFIG_HAVE_FITS_IS_REENTRANT == 1
  432       if(p->cp.numthreads>1 && fits_is_reentrant()==0)
  433         {
  434           fprintf(stderr, "WARNING: CFITSIO was not configured with the "
  435                   "`--enable-reentrant' option but you have asked to crop "
  436                   "on %zu threads. Therefore only one thread will be used.\n\n"
  437                   "Please run the following command to learn more about "
  438                   "configuring CFITSIO:\n\n"
  439                   "    $ info gnuastro CFITSIO", p->cp.numthreads);
  440           p->cp.numthreads=1;
  441         }
  442 #else
  443       if(p->cp.numthreads>1)
  444         {
  445           fprintf(stderr, "WARNING: the installed CFITSIO version doesn't "
  446                   "have `fits_is_reentrant' function (it is older than "
  447                   "version 3.30). But you have asked to crop on %zu threads."
  448                   "Therefore only one thread will be used.\n\n"
  449                   "To avoid this warning, you can set the number of threads "
  450                   "to one with `-N1' or update your installation of CFITSIO.",
  451                   p->cp.numthreads);
  452           p->cp.numthreads=1;
  453         }
  454 #endif
  455 
  456       /* Make sure the given output is a directory. */
  457       gal_checkset_check_dir_write_add_slash(&p->cp.output);
  458     }
  459   else
  460     {
  461       p->cp.numthreads=1;
  462       p->outnameisfile=gal_checkset_dir_0_file_1(p->cp.output,
  463                                                  p->cp.dontdelete);
  464     }
  465 }
  466 
  467 
  468 
  469 
  470 
  471 
  472 
  473 
  474 
  475 
  476 
  477 
  478 
  479 
  480 
  481 
  482 
  483 
  484 
  485 
  486 /**************************************************************/
  487 /***************       Preparations         *******************/
  488 /**************************************************************/
  489 /* When the crop is defined by its center, the final width that we need
  490    must be in actual number of pixels (an integer). But the user's values
  491    can be in WCS mode or even in image mode, they may be non-integers. */
  492 static void
  493 ui_set_img_sizes(struct cropparams *p)
  494 {
  495   gal_data_t *newwidth;
  496   size_t i, ndim=p->imgs->ndim;
  497   double pwidth, pcheckcenter, *warray;
  498 
  499   /* Make sure a width value is actually given. */
  500   if(p->width==NULL)
  501     error(EXIT_FAILURE, 0, "no crop width specified. When crops are "
  502           "defined by their center (with `--center' or `--catalog') a "
  503           "width is necessary (using the `--width' option)");
  504 
  505   /* Make sure that the width array only has one element or the same number
  506      of elements as the input's dimensions. */
  507   if(p->width->size!=ndim && p->width->size!=1)
  508     error(EXIT_FAILURE, 0, "%zu values give to `--width', but input is %zu "
  509           "dimensions. It can only take either one value (same width in all "
  510           "dimensions), or the same number as the input's dimensions",
  511           p->width->size, ndim);
  512 
  513   /* If the width array has only one value, that single value should be
  514      used for all dimensions. */
  515   if(p->width->size==1)
  516     {
  517       /* Allocate the new width dataset. */
  518       newwidth=gal_data_alloc(NULL, p->width->type, 1, &ndim, NULL, 0, -1,
  519                               NULL, NULL, NULL);
  520 
  521       /* Fill the new width. */
  522       warray=newwidth->array;
  523       for(i=0;i<ndim;++i) warray[i] = *(double *)(p->width->array);
  524 
  525       /* Free the old (single element) width dataset and put the new one in
  526          its place. */
  527       gal_data_free(p->width);
  528       p->width=newwidth;
  529     }
  530   else warray=p->width->array;
  531 
  532   /* WCS mode. */
  533   if(p->mode==IMGCROP_MODE_WCS)
  534     {
  535       /* Fill in the widths depending on the mode. */
  536       for(i=0;i<ndim;++i)
  537         {
  538           /* Convert the width in units of the input's WCS into pixels. */
  539           pwidth = warray[i]/p->pixscale[i];
  540           if(pwidth<3 || pwidth>50000)
  541             error(EXIT_FAILURE, 0, "value %g (requested width along "
  542                   "dimension %zu) translates to %.0f pixels on this "
  543                   "dataset. This is probably not what you wanted. Note "
  544                   "that the dataset's resolution in this dimension is "
  545                   "%g.\n\n"
  546                   "You can do the conversion to the dataset's WCS units "
  547                   "prior to calling Crop. Alternatively, you can specify "
  548                   "all the coordinates/sizes in image (not WCS) units and "
  549                   "use the `--mode=img' option", warray[i], i+1, pwidth,
  550                   p->pixscale[i]);
  551 
  552           /* Write the single valued width in WCS and the image width for
  553              this dimension. */
  554           p->iwidth[i]=GAL_DIMENSION_FLT_TO_INT(pwidth);
  555           if(p->iwidth[i]%2==0)
  556             {
  557               p->iwidth[i] += 1;
  558               warray[i]    += p->pixscale[i];
  559             }
  560         }
  561 
  562       /* Checkcenter: */
  563       if(p->incheckcenter)
  564         pcheckcenter=((double *)(p->incheckcenter->array))[0]/p->pixscale[0];
  565     }
  566   /* Image mode. */
  567   else
  568     {
  569       /* The width (along each dimension). */
  570       for(i=0;i<ndim;++i)
  571         {
  572           p->iwidth[i]=GAL_DIMENSION_FLT_TO_INT(warray[i]);
  573           if(p->iwidth[i]%2==0) p->iwidth[i] += 1;
  574         }
  575 
  576       /* Checkcenter: */
  577       if(p->incheckcenter)
  578         {
  579           /* Write the double value into the temporary variable */
  580           pcheckcenter=((double *)(p->incheckcenter->array))[0];
  581 
  582           /* In image-mode it has to be an integer. */
  583           if( ceilf(pcheckcenter)!=pcheckcenter )
  584             error(EXIT_FAILURE, 0, "%g is not an integer. When cropping in "
  585                   "image-mode, the number of pixels to check in the "
  586                   "center must be an integer", pcheckcenter);
  587         }
  588     }
  589 
  590   /* Finalize the number of central pixels to check. */
  591   if(p->incheckcenter)
  592     {
  593       /* Convert the floating point value to an integer. */
  594       p->checkcenter=GAL_DIMENSION_FLT_TO_INT(pcheckcenter);
  595 
  596       /* If `checkcenter' isn't zero, but is even, convert it to an odd
  597          number (so the actual center can be checked). */
  598       if(p->checkcenter && p->checkcenter%2==0) p->checkcenter += 1;
  599     }
  600 
  601   /* For a check:
  602   printf("Width: "); for(i=0;i<ndim;++i) printf("\t%ld\n\t", p->iwidth[i]);
  603   exit(0);
  604   */
  605 }
  606 
  607 
  608 
  609 
  610 
  611 static void
  612 ui_read_cols(struct cropparams *p)
  613 {
  614   char colname[100];
  615   gal_data_t *cols, *tmp, *corrtype=NULL;
  616   gal_list_str_t *colstrs=NULL, *extracolstr, *lastcolstr;
  617   size_t i, ncoordcols, counter=0, dcounter=0, ndim=p->imgs->ndim;
  618 
  619   /* See if the number of columns given for coordinates corresponds to the
  620      number of dimensions of the input dataset. */
  621   if(p->coordcol)
  622     {
  623       /* Check if the number of columns given for coordinates is the same
  624          as the number of dimensions in the input dataset(s). */
  625       ncoordcols=gal_list_str_number(p->coordcol);
  626       if( ncoordcols < ndim)
  627         error(EXIT_FAILURE, 0, "`--coordcol' was called %zu times, but the "
  628               "input dataset%s %zu dimensions. Recall that through "
  629               "`--coordcol' you are specifying the columns containing the "
  630               "coordinates of the center of the crop in a catalog",
  631               ncoordcols, (p->numin==1?" has":"s have"), ndim);
  632 
  633       /* If the number of given columns is more than the input's
  634          dimensions, then we'll just delete all the unnecessary columns. */
  635       else if( ncoordcols > ndim )
  636         {
  637           /* Go over the columns find the last, but first initialize the
  638              two (`lastcolstr' to avoid compiler warnings). */
  639           lastcolstr=extracolstr=p->coordcol;
  640           for(i=0;i<ndim;++i)
  641             {
  642               /* Keep the last node if on the last (useful) column. */
  643               if(i==ndim-1) lastcolstr=extracolstr;
  644 
  645               /* Go onto the next one. */
  646               extracolstr=extracolstr->next;
  647             }
  648 
  649           /* Set the `next' element of the last node to NULL and free the
  650              extra ones. */
  651           lastcolstr->next=NULL;
  652           gal_list_str_free(extracolstr, 1);
  653         }
  654     }
  655   else
  656     error(EXIT_FAILURE, 0, "no coordinate columns specified. When a catalog"
  657           "is given, it is necessary to identify which columns identify "
  658           "the coordinate values in which dimension.\n\n"
  659           "You can do this by calling `--coordcol' multiple times, the "
  660           "order must be in the same order as the input's dimensions. "
  661           "For more information on how to select columns in Gnuastro, "
  662           "please run the following command:\n\n"
  663           "    $ info gnuastro \"Selecting table columns\"");
  664 
  665 
  666   /* If a name column was also given, the put that as the first column to
  667      read, otherwise just use the given set of columns (in the same
  668      order). */
  669   if(p->namecol)
  670     {
  671       gal_list_str_add(&colstrs, p->namecol, 0);
  672       colstrs->next=p->coordcol;
  673     }
  674   else colstrs=p->coordcol;
  675 
  676 
  677   /* Read the desired columns from the file. */
  678   cols=gal_table_read(p->catname, p->cathdu, NULL, colstrs, p->cp.searchin,
  679                       p->cp.ignorecase, p->cp.minmapsize, NULL);
  680   if(cols==NULL)
  681     error(EXIT_FAILURE, 0, "%s: is empty! No usable information "
  682           "(un-commented lines) could be read from this file",
  683           gal_fits_name_save_as_string(p->catname, p->cathdu));
  684 
  685 
  686   /* Set the number of objects (rows in each column). */
  687   p->numout=cols->size;
  688 
  689 
  690   /* Make sure more columns were not read (the name matchings might result
  691      in more than one column being read from the inputs). */
  692   if( gal_list_data_number(cols) != ndim + (p->namecol!=NULL) )
  693     gal_tableintern_error_col_selection(p->catname, p->cathdu, "too many "
  694                                         "columns were selected by the given "
  695                                         "values to the options ending in "
  696                                         "`col'.");
  697 
  698 
  699   /* Put the information in each column in the proper place. */
  700   while(cols!=NULL)
  701     {
  702       /* Pop out the top node. */
  703       tmp=gal_list_data_pop(&cols);
  704 
  705       /* See which column it is. */
  706       switch(++counter)
  707         {
  708         case 1:
  709           if(p->namecol)
  710             {
  711               sprintf(colname, "crop name prefix");
  712               corrtype = (tmp->type==GAL_TYPE_STRING ? tmp
  713                           : gal_data_copy_to_new_type_free(tmp,
  714                                                             GAL_TYPE_STRING));
  715               p->name=corrtype->array;
  716             }
  717           else
  718             {
  719               sprintf(colname, "position in dimension %zu", dcounter+1);
  720               corrtype=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT64);
  721               p->centercoords[ dcounter++ ]=corrtype->array;
  722             }
  723           break;
  724 
  725         default:
  726           sprintf(colname, "position in dimension %zu", dcounter+1);
  727           corrtype=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT64);
  728           p->centercoords[ dcounter++ ] = corrtype->array;
  729         }
  730 
  731       /* Sanity check and clean up.  Note that it might happen that the
  732          input structure is already freed. In that case, `corrtype' will be
  733          NULL. */
  734       if(corrtype)
  735         {
  736           /* Make sure there are no blank values in this column. */
  737           if( gal_blank_present(corrtype, 1) )
  738             error(EXIT_FAILURE, 0, "%s: column with %s has blank values. "
  739                   "Input columns must not contain blank values",
  740                   gal_fits_name_save_as_string(p->catname, p->cathdu),
  741                   colname);
  742 
  743           /* Free the unnecessary sturcture information. The correct-type
  744              (`corrtype') data structure's array is necessary for later
  745              steps, so its pointer has been copied in the main program's
  746              structure. Hence, we should set the structure's pointer to
  747              NULL so the important data isn't freed.*/
  748           corrtype->array=NULL;
  749           gal_data_free(corrtype);
  750           corrtype=NULL;
  751         }
  752     }
  753 }
  754 
  755 
  756 
  757 
  758 
  759 static void
  760 ui_prepare_center(struct cropparams *p)
  761 {
  762   double *carray;
  763   size_t i, ndim=p->imgs->ndim;
  764 
  765   /* Allocate space to keep the central positions. */
  766   errno=0;
  767   p->centercoords=malloc(ndim*sizeof *p->centercoords);
  768   if( p->centercoords==NULL )
  769     error(EXIT_FAILURE, 0, "%s: %zu bytes for `p->centercoords'",
  770           __func__, ndim*sizeof *p->centercoords);
  771 
  772 
  773   /* Set the integer widths of the crop(s) when defined by center. */
  774   ui_set_img_sizes(p);
  775 
  776   /* For a catalog, we have a separate function, but for a single center
  777      value, put the center values into an array. This will essentially
  778      simulate a catalog with one row. So from this point on, there is no
  779      difference between a catalog input and a central position input. */
  780   if(p->catname)
  781     ui_read_cols(p);
  782   else
  783     {
  784       carray=p->center->array;
  785       for(i=0;i<ndim;++i)
  786         {
  787           p->centercoords[i]=gal_pointer_allocate(GAL_TYPE_FLOAT64,
  788                                                   1, 0, __func__,
  789                                                   "p->centercoords[i]");
  790           p->centercoords[i][0]=carray[i];
  791         }
  792     }
  793 }
  794 
  795 
  796 
  797 
  798 
  799 
  800 /* Add all the columns of the log file. Just note that since this is a
  801    linked list, we have to add them in the opposite order. */
  802 static void
  803 ui_make_log(struct cropparams *p)
  804 {
  805   char *comment;
  806 
  807   /* Return if no long file was requested. */
  808   if(p->cp.log==0) return;
  809 
  810   /* Column to specify if the central pixels are filled. */
  811   if( asprintf(&comment, "Are the central pixels filled? (1: yes, 0: no, "
  812                "%u: not checked)", GAL_BLANK_UINT8)<0 )
  813     error(EXIT_FAILURE, 0, "%s: asprintf allocation", __func__);
  814   gal_list_data_add_alloc(&p->log, NULL, GAL_TYPE_UINT8, 1, &p->numout,
  815                           NULL, 1, p->cp.minmapsize, "CENTER_FILLED",
  816                           "bool", comment);
  817   free(comment);
  818 
  819   /* Column for number of datasets used in this crop. */
  820   gal_list_data_add_alloc(&p->log, NULL, GAL_TYPE_UINT16, 1, &p->numout,
  821                           NULL, 1, p->cp.minmapsize, "NUM_INPUTS", "count",
  822                           "Number of input datasets used to make this crop.");
  823 
  824   /* Filename of crop. */
  825   gal_list_data_add_alloc(&p->log, NULL, GAL_TYPE_STRING, 1, &p->numout,
  826                           NULL, 1, p->cp.minmapsize, "CROP_NAME", "name",
  827                           "File name of crop.");
  828 }
  829 
  830 
  831 
  832 
  833 
  834 void
  835 ui_preparations(struct cropparams *p)
  836 {
  837   fitsfile *tmpfits;
  838   struct inputimgs *img;
  839   int status, firsttype=0;
  840   size_t input_counter, firstndim=0;
  841 
  842 
  843   /* For polygon and section, there should be no center checking. */
  844   if(p->polygon || p->section)
  845     p->checkcenter=0;
  846 
  847 
  848   /* Allocate space for all the input images. This is done here because
  849      WCSLIB is unfortunately not thread-safe when reading the WCS
  850      information from the FITS files. In cases where the number of cropped
  851      images are more than the input images, this can also be a preformance
  852      boost because each image information is only read once.
  853 
  854      The images are filled in opposite order because we used a linked list
  855      to read them in, which is a first in first out structure.*/
  856   errno=0;
  857   p->imgs=malloc(p->numin*sizeof *p->imgs);
  858   if(p->imgs==NULL)
  859     error(EXIT_FAILURE, errno, "%s: %zu bytes for p->imgs",
  860           __func__, p->numin*sizeof *p->imgs);
  861 
  862 
  863   /* Fill in the WCS information of each image. */
  864   input_counter=p->numin;
  865   while(p->inputs)
  866     {
  867       /* Pop from the list of input images and get the info. */
  868       status=0;
  869       img=&p->imgs[--input_counter];
  870       img->name=gal_list_str_pop(&p->inputs);
  871       tmpfits=gal_fits_hdu_open_format(img->name, p->cp.hdu, 0);
  872       gal_fits_img_info(tmpfits, &p->type, &img->ndim, &img->dsize,
  873                         NULL, NULL);
  874       img->wcs=gal_wcs_read_fitsptr(tmpfits, p->hstartwcs, p->hendwcs,
  875                                     &img->nwcs);
  876       if(img->wcs)
  877         {
  878           gal_wcs_decompose_pc_cdelt(img->wcs);
  879           status=wcshdo(0, img->wcs, &img->nwcskeys, &img->wcstxt);
  880           if(status)
  881             error(EXIT_FAILURE, 0, "wcshdo ERROR %d: %s", status,
  882                   wcs_errmsg[status]);
  883         }
  884       else
  885         if(p->mode==IMGCROP_MODE_WCS)
  886           error(EXIT_FAILURE, 0, "the WCS structure of %s (hdu: %s) "
  887                 "image is not recognized. So WCS mode cannot be used "
  888                 "as input coordinates. You can try with pixel coordinates "
  889                 "with `--mode=img'", img->name, p->cp.hdu);
  890       fits_close_file(tmpfits, &status);
  891       gal_fits_io_error(status, NULL);
  892 
  893       /* Make sure all the images have the same type and dimensions. */
  894       if(firsttype==0)
  895         {
  896           /* Set the basic information. */
  897           firsttype = p->type;
  898           firstndim = img->ndim;
  899           p->bitnul = gal_fits_key_img_blank(p->type);
  900 
  901           /* Make sure the number of dimensions is supported. */
  902           if(firstndim>MAXDIM)
  903             error(EXIT_FAILURE, 0, "%s: is as %zu dimensional dataset, Crop "
  904                   "currently only supports a maximum of %d dimensions",
  905                   img->name, firstndim, MAXDIM);
  906 
  907           /* Make sure the number of coordinates given for center
  908              correspond to the dimensionality of the data. */
  909           if(p->center && p->center->size!=firstndim)
  910             error(EXIT_FAILURE, 0, "%s (hdu %s) has %zu dimensions, but "
  911                   "%zu coordinates were given to `--center'", img->name,
  912                   p->cp.hdu, firstndim, p->center->size);
  913         }
  914       else
  915         {
  916           if(firsttype!=p->type)
  917             error(EXIT_FAILURE, 0, "%s: type is `%s' while previous input(s) "
  918                   "were `%s' type. All inputs must have the same pixel data "
  919                   "type.\n\nYou can use Gnuastro's Arithmetic program to "
  920                   "convert `%s' to `%s', please run this command for more "
  921                   "information (press `SPACE' for going down and `q' to "
  922                   "return to the command-line):\n\n"
  923                   "    $ info Arithmetic\n",
  924                   img->name, gal_type_name(p->type, 1),
  925                   gal_type_name(firsttype, 1), img->name,
  926                   gal_type_name(p->type, 1));
  927           if(firstndim!=img->ndim)
  928             error(EXIT_FAILURE, 0, "%s: type has %zu dimensions, while "
  929                   "previous input(s) had %zu dimensions. All inputs must "
  930                   "have the same number of dimensions", img->name, img->ndim,
  931                   firstndim);
  932         }
  933 
  934       /* In WCS mode, we need some additional preparations. */
  935       if(p->mode==IMGCROP_MODE_WCS) wcsmode_check_prepare(p, img);
  936     }
  937 
  938 
  939   /* Unify central crop methods into `p->centercoords'. */
  940   if(p->catname || p->center)
  941     ui_prepare_center(p);
  942 
  943 
  944   /* `ui_read_cols' set the number of output crops when a catalog was
  945      given, in all other cases, we only have one output. */
  946   if(p->catname==NULL) p->numout=1;
  947 
  948 
  949   /* Prepare the log file if the user has asked for it. */
  950   ui_make_log(p);
  951 }
  952 
  953 
  954 
  955 
  956 
  957 
  958 
  959 
  960 
  961 
  962 
  963 
  964 
  965 
  966 
  967 
  968 
  969 
  970 
  971 
  972 /**************************************************************/
  973 /************         Set the parameters          *************/
  974 /**************************************************************/
  975 
  976 void
  977 ui_read_check_inputs_setup(int argc, char *argv[], struct cropparams *p)
  978 {
  979   char *msg;
  980   struct timeval t1;
  981   struct gal_options_common_params *cp=&p->cp;
  982 
  983 
  984   /* Include the parameters necessary for argp from this program (`args.h')
  985      and for the common options to all Gnuastro (`commonopts.h'). We want
  986      to directly put the pointers to the fields in `p' and `cp', so we are
  987      simply including the header here to not have to use long macros in
  988      those headers which make them hard to read and modify. This also helps
  989      in having a clean environment: everything in those headers is only
  990      available within the scope of this function. */
  991 #include <gnuastro-internal/commonopts.h>
  992 #include "args.h"
  993 
  994 
  995   /* Initialize the options and necessary information.  */
  996   ui_initialize_options(p, program_options, gal_commonopts_options);
  997 
  998 
  999   /* Read the command-line options and arguments. */
 1000   errno=0;
 1001   if(argp_parse(&thisargp, argc, argv, 0, 0, p))
 1002     error(EXIT_FAILURE, errno, "parsing arguments");
 1003 
 1004 
 1005   /* Read the configuration files and set the common values. */
 1006   gal_options_read_config_set(&p->cp);
 1007 
 1008 
 1009   /* Read the options into the program's structure, and check them and
 1010      their relations prior to printing. */
 1011   ui_read_check_only_options(p);
 1012 
 1013 
 1014   /* Print the option values if asked. Note that this needs to be done
 1015      after the option checks so un-sane values are not printed in the
 1016      output state. */
 1017   gal_options_print_state(&p->cp);
 1018 
 1019 
 1020   /* Check that the options and arguments fit well with each other. Note
 1021      that arguments don't go in a configuration file. So this test should
 1022      be done after (possibly) printing the option values. */
 1023   ui_check_options_and_arguments(p);
 1024 
 1025 
 1026   /* To see how long it takes to read meta-data. */
 1027   if(!p->cp.quiet) gettimeofday(&t1, NULL);
 1028 
 1029 
 1030   /* Read/allocate all the necessary starting arrays. */
 1031   ui_preparations(p);
 1032 
 1033 
 1034   /* Report timing: */
 1035   if(!p->cp.quiet)
 1036     {
 1037       printf(PROGRAM_NAME" "PACKAGE_VERSION" started on %s",
 1038              ctime(&p->rawtime));
 1039       if(p->cp.numthreads>1)
 1040         printf("  - Using %zu CPU thread%s\n", p->cp.numthreads,
 1041                p->cp.numthreads==1 ? "." : "s.");
 1042       if(p->checkcenter)
 1043         printf("  - Number of central pixels to check for blank: %zu\n",
 1044                p->checkcenter);
 1045       if( asprintf(&msg, "Read metadata of %zu dataset%s.", p->numin,
 1046                    p->numin>1 ? "s" : "")<0 )
 1047         error(EXIT_FAILURE, 0, "%s: asprintf allocation", __func__);
 1048       gal_timing_report(&t1, msg, 1);
 1049       if(p->numout>1)
 1050         {
 1051           if( asprintf(&msg, "Will try making %zu crops (from catalog).",
 1052                        p->numout)<0 )
 1053             error(EXIT_FAILURE, 0, "%s: asprintf allocation", __func__);
 1054           gal_timing_report(NULL, msg, 1);
 1055         }
 1056     }
 1057 
 1058 }
 1059 
 1060 
 1061 
 1062 
 1063 
 1064 
 1065 
 1066 
 1067 
 1068 
 1069 
 1070 
 1071 
 1072 
 1073 
 1074 
 1075 
 1076 
 1077 
 1078 
 1079 /**************************************************************/
 1080 /************      Free allocated, report         *************/
 1081 /**************************************************************/
 1082 void
 1083 ui_free_report(struct cropparams *p, struct timeval *t1)
 1084 {
 1085   size_t i;
 1086 
 1087   /* Free the simple arrays (if they were set). */
 1088   gal_data_free(p->center);
 1089   if(p->cp.hdu) free(p->cp.hdu);
 1090   if(p->cathdu) free(p->cathdu);
 1091   if(p->catname) free(p->catname);
 1092 
 1093   /* The arguments (note that the values were not allocated). */
 1094   gal_list_str_free(p->inputs, 0);
 1095 
 1096   /* Free the name/ array.  */
 1097   if(p->name)
 1098     {
 1099       for(i=0;i<p->numout;++i)
 1100         free(p->name[i]);
 1101       free(p->name);
 1102     }
 1103 
 1104   /* Free the log information. */
 1105   if(p->cp.log) gal_list_data_free(p->log);
 1106 
 1107   /* Print the final message. */
 1108   if(!p->cp.quiet)
 1109     gal_timing_report(t1, PROGRAM_NAME" finished in: ", 0);
 1110 }