gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master 0e344fe 086/125: Warp now uses gal_data_t and


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 0e344fe 086/125: Warp now uses gal_data_t and all its fruits
Date: Sun, 23 Apr 2017 22:36:44 -0400 (EDT)

branch: master
commit 0e344fe55b60deeb9081ffe690e00e109db83fa6
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Warp now uses gal_data_t and all its fruits
    
    The Warp program now uses all the new features offered by `gal_data_t' in
    this branch. Several major changes were made to make it more user friendly
    as described below:
    
     - The old `--nowcscorrection' option has been given a more clear name of
       `--keepwcs'. With this option, Warp will not apply the warp the input's
       WCS structure.
    
     - The old `--maxblankfrac' option has been changed to
       `--coveredfrac'. Until now, Warp would only look for the fraction of
       input blank/NaN pixel area over the output pixel. But this would be
       useless on the edges of the image. So the new `--coveredfrac' option
       takes the acceptable fraction of output pixel area that must be covered
       by input pixels in order to give that output pixel a value. When given a
       sufficiently high value (1.0 is the largest possible), it will allow the
       user to not be bothered by bad edge values which are caused because of
       not having any data outside the image.
    
     - The old `--nofitscorrect' option has been changed to `--centeroncorner'
       to be more clear. The new option is now more general than
       before. Before, it would only work on 2D matrixes and modular warpings,
       but now, it is general and happens after the final input Matrix is
       ready, so it even applies to 3D raw input matrix. The previous case was
       confusing both for the users and developers.
    
     - The old `--zerofornoinput' option has been removed. If the user doesn't
       want blank pixels for regions were there was no data, they can use
       Arithmetic.
    
     - The old `--doubletype' option has been removed, since the common option
       `--type' now comes in from the infra-structure which is much more
       flexible and allows the user to set any type, not just double.
    
     - A new `func' element was added to `argp_option' that will be used by the
       option parsers to immediately parse the value and store the value in a
       lower-level way that can be used by the programs more efficiently. This
       was mainly done because of the modular warpings of Warp: they have
       differnt option names, but because order matters in them, they must all
       be kept in one lower-level linked list. After its implementation, it is
       now also used for the common options that take strings for values that
       are internally stored as integer constants: the common options `--type',
       `--tableformat', and `--searchin'. When writing the options and their
       values, it will also use the same function to retrieve the static
       string. Unfortunately for the time being, it doesn't print the values of
       the modular warpings of Warp, but later we can implement it, maybe the
       matrix option alone (which contains all the warping information) would
       be enough.
    
    This completes task #14365 and task #14368.
---
 .gitignore                |   2 +-
 bin/mkprof/ui.c           |   9 +-
 bin/warp/Makefile.am      |   2 +-
 bin/warp/args.h           | 139 ++++++--
 bin/warp/astwarp.conf     |   6 +-
 bin/warp/main.c           |   2 +-
 bin/warp/main.h           |  39 +--
 bin/warp/ui.c             | 832 ++++++++++++++++++++++++++++++++++++++++------
 bin/warp/ui.h             |   3 +-
 bin/warp/warp.c           | 145 ++++----
 bin/warp/warp.h           |   2 +-
 bootstrap.conf            |   7 +-
 doc/gnuastro.texi         | 386 +++++++++------------
 lib/commonopts.h          |   8 +-
 lib/fits.c                |  13 +-
 lib/gnuastro/fits.h       |  14 +-
 lib/gnuastro/linkedlist.h |  26 ++
 lib/gnuastro/table.h      |   6 +
 lib/linkedlist.c          | 110 ++++++
 lib/options.c             | 270 +++++++++------
 lib/options.h             |  22 +-
 lib/table.c               |  63 ++--
 lib/wcs.c                 |   2 +-
 tests/warp/homographic.sh |   2 +-
 tests/warp/warp_scale.sh  |   2 +-
 tmpfs-config-make         |   2 +-
 26 files changed, 1474 insertions(+), 640 deletions(-)

diff --git a/.gitignore b/.gitignore
index 1b4ee05..40a612f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -84,7 +84,6 @@ astmkprof
 astheader
 runtest.sh
 astmknoise
-astimgstat
 config.sub
 install-sh
 aclocal.m4
@@ -103,6 +102,7 @@ doc/fdl.texi
 config.status
 doc/stamp-vti
 astarithmetic
+aststatistics
 astnoisechisel
 astsubtractsky
 autom4te.cache
diff --git a/bin/mkprof/ui.c b/bin/mkprof/ui.c
index 85b851c..cdc9633 100644
--- a/bin/mkprof/ui.c
+++ b/bin/mkprof/ui.c
@@ -171,11 +171,12 @@ ui_initialize_options(struct mkprofparams *p,
   struct gal_options_common_params *cp=&p->cp;
 
   /* Set the necessary common parameters structure. */
-  cp->poptions           = program_options;
   cp->program_name       = PROGRAM_NAME;
   cp->program_exec       = PROGRAM_EXEC;
   cp->program_bibtex     = PROGRAM_BIBTEX;
   cp->program_authors    = PROGRAM_AUTHORS;
+  cp->poptions           = program_options;
+  cp->numthreads         = gal_threads_number();
   cp->coptions           = gal_commonopts_options;
 
   /* Default program parameters. */
@@ -202,12 +203,6 @@ ui_initialize_options(struct mkprofparams *p,
         cp->coptions[i].mandatory=GAL_OPTIONS_MANDATORY;
         break;
       }
-
-
-  /* Read the number of threads available to the user, this should be done
-     before reading command-line and configuration file options, since they
-     can change it.  */
-  cp->numthreads=gal_threads_number();
 }
 
 
diff --git a/bin/warp/Makefile.am b/bin/warp/Makefile.am
index 1f9706d..9cddfaa 100644
--- a/bin/warp/Makefile.am
+++ b/bin/warp/Makefile.am
@@ -30,7 +30,7 @@ bin_PROGRAMS = astwarp
 
 astwarp_LDADD = -lgnuastro
 
-astwarp_SOURCES = main.c ui.c imgwarp.c
+astwarp_SOURCES = main.c ui.c warp.c
 
 EXTRA_DIST = main.h authors-cite.h args.h ui.h warp.h
 
diff --git a/bin/warp/args.h b/bin/warp/args.h
index ee1d750..56b5fd8 100644
--- a/bin/warp/args.h
+++ b/bin/warp/args.h
@@ -64,27 +64,27 @@ struct argp_option program_options[] =
 
     /* Output. */
     {
-      "keepinputwcs",
-      ARGS_OPTION_KEY_KEEPINPUTWCS,
+      "keepwcs",
+      ARGS_OPTION_KEY_KEEPWCS,
       0,
       0,
       "Do not apply warp to input's WCS",
       GAL_OPTIONS_GROUP_OUTPUT,
-      &p->keepinputwcs,
+      &p->keepwcs,
       GAL_OPTIONS_NO_ARG_TYPE,
       GAL_OPTIONS_RANGE_0_OR_1,
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
     {
-      "maxblankfrac",
-      ARGS_OPTION_KEY_MAXBLANKFRAC,
+      "coveredfrac",
+      ARGS_OPTION_KEY_COVEREDFRAC,
       "FLT",
       0,
-      "Maximum fraction of area covered by blank.",
+      "Acceptable fraction of output pixel covered.",
       GAL_OPTIONS_GROUP_OUTPUT,
-      &p->maxblankfrac,
-      GAL_DATA_TYPE_FLOAT,
+      &p->coveredfrac,
+      GAL_DATA_TYPE_FLOAT64,
       GAL_OPTIONS_RANGE_GE_0_LE_1,
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
@@ -101,31 +101,132 @@ struct argp_option program_options[] =
       ARGS_OPTION_KEY_ALIGN,
       0,
       0,
-      "Align the image and celestial axes."
+      "Align the image and celestial axes.",
       ARGS_GROUP_WARPS,
-      &p->align,
-      GAL_OPTIONS_NO_ARG_TYPE,
-      GAL_OPTIONS_RANGE_0_OR_1,
+      0,
+      GAL_DATA_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
+      GAL_OPTIONS_NOT_SET,
+      ui_add_to_modular_warps_ll
+    },
+    {
+      "rotate",
+      ARGS_OPTION_KEY_ROTATE,
+      "FLT",
+      0,
+      "Rotate by the given angle in degrees.",
+      ARGS_GROUP_WARPS,
+      0,
+      GAL_DATA_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_add_to_modular_warps_ll
+    },
+    {
+      "scale",
+      ARGS_OPTION_KEY_SCALE,
+      "FLT[,FLT]",
+      0,
+      "Scale along the given axis(es).",
+      ARGS_GROUP_WARPS,
+      0,
+      GAL_DATA_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_add_to_modular_warps_ll
+    },
+    {
+      "flip",
+      ARGS_OPTION_KEY_FLIP,
+      "INT[,INT]",
+      0,
+      "Flip along the given axis(es).",
+      ARGS_GROUP_WARPS,
+      0,
+      GAL_DATA_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_add_to_modular_warps_ll
+    },
+    {
+      "shear",
+      ARGS_OPTION_KEY_SHEAR,
+      "FLT[,FLT]",
+      0,
+      "Shear along the given axis(es).",
+      ARGS_GROUP_WARPS,
+      0,
+      GAL_DATA_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_add_to_modular_warps_ll
+    },
+    {
+      "translate",
+      ARGS_OPTION_KEY_TRANSLATE,
+      "FLT[,FLT]",
+      0,
+      "Translate along the given axis(es).",
+      ARGS_GROUP_WARPS,
+      0,
+      GAL_DATA_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_add_to_modular_warps_ll
+    },
+    {
+      "project",
+      ARGS_OPTION_KEY_PROJECT,
+      "FLT[,FLT]",
+      0,
+      "Project along the given axis(es).",
+      ARGS_GROUP_WARPS,
+      0,
+      GAL_DATA_TYPE_INVALID,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_add_to_modular_warps_ll
     },
     {
-      "type",
-      ARGS_OPTION_KEY_TYPE,
+      "matrix",
+      ARGS_OPTION_KEY_MATRIX,
       "STR",
       0,
-      "uchar, short, long, longlong, float, double."
-      GAL_OPTIONS_GROUP_OUTPUT,
-      &p->typestr,
-      GAL_DATA_TYPE_STRING,
+      "Raw transformation matrix, highest priority.",
+      ARGS_GROUP_WARPS,
+      &p->matrix,
+      GAL_DATA_TYPE_INVALID,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_add_to_modular_warps_ll
+    },
+    {
+      "centeroncorner",
+      ARGS_OPTION_KEY_CENTERONCORNER,
+      0,
+      0,
+      "Center of coordinates on first pixel corner.",
+      ARGS_GROUP_WARPS,
+      &p->centeroncorner,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
 
 
 
 
+
+
     {0}
   };
 
diff --git a/bin/warp/astwarp.conf b/bin/warp/astwarp.conf
index 9585c5a..871f5a8 100644
--- a/bin/warp/astwarp.conf
+++ b/bin/warp/astwarp.conf
@@ -21,4 +21,8 @@
  hdu           0
 
 # Output:
- maxblankfrac  0.8
\ No newline at end of file
+ coveredfrac   1.0
+
+# Common parameters
+ type          float32
+ minmapsize    1000000000
\ No newline at end of file
diff --git a/bin/warp/main.c b/bin/warp/main.c
index f5b8dbd..bb1799d 100644
--- a/bin/warp/main.c
+++ b/bin/warp/main.c
@@ -46,7 +46,7 @@ main (int argc, char *argv[])
   ui_read_check_inputs_setup(argc, argv, &p);
 
   /* Run Warp */
-  imgwarp(&p);
+  warp(&p);
 
   /* Free all non-freed allocations. */
   ui_free_report(&p, &t1);
diff --git a/bin/warp/main.h b/bin/warp/main.h
index b951ac4..ca224fd 100644
--- a/bin/warp/main.h
+++ b/bin/warp/main.h
@@ -37,46 +37,23 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
-
-struct optionwarpsll
-{
-  int                   type;
-  double                  v1;
-  double                  v2;
-  struct optionwarpsll *next;
-};
-
-
-
-
-
+/* Main program structure. */
 struct warpparams
 {
   /* From command-line */
   struct gal_options_common_params cp; /* Common parameters.             */
-  struct optionwarpsll *owll;    /* List of 2D rotations.                */
   char         *inputname;  /* Name of input file.                       */
   size_t        hstartwcs;  /* Header keyword No. to start reading WCS.  */
   size_t          hendwcs;  /* Header keyword No. to end reading WCS.    */
-  unsigned char keepinputwcs;  /* Wrap the warped/transfomed pixels.     */
-  float      maxblankfrac;  /* Maximum fraction of blank pixel in out.   */
-  char           *typestr;  /* Type of output image.                     */
-  unsigned char     align;  /* Align the image with celestial coord.     */
-  char         *rotatestr;  /* String given for rotation.                */
-  char          *scalestr;  /* String given for scaling.                 */
-  char           *flipstr;  /* String given for flipping.                */
-  char          *shearstr;  /* String given for shearing.                */
-  char      *translatestr;  /* String given for translation.             */
-  char        *projectstr;  /* String given for projection.              */
-  char         *matrixstr;  /* String containing transform elements.     */
+  uint8_t         keepwcs;  /* Wrap the warped/transfomed pixels.        */
+  uint8_t  centeroncorner;  /* Shift center by 0.5 before and after.     */
+  double      coveredfrac;  /* Acceptable fraction of output covered.    */
 
   /* Internal parameters: */
-  gal_data_t       *input;  /* Name of input FITS file.                  */
-  int             outtype;  /* Output type.                              */
-  double        matrix[9];  /* Warp/Transformation matrix.               */
-  double          *output;  /* Warped image array.                       */
-  size_t        onaxes[2];  /* Output image size                         */
-  size_t        knaxes[2];  /* Output image size                         */
+  gal_data_t       *input;  /* Input data structure.                     */
+  gal_data_t      *output;  /* output data structure.                    */
+  gal_data_t      *matrix;  /* Warp/Transformation matrix.               */
+  gal_data_t   *modularll;  /* List of modular warpings.                 */
   double         *inverse;  /* Inverse of the input matrix.              */
   time_t          rawtime;  /* Starting time of the program.             */
   size_t       extinds[4];  /* Indexs of the minimum and maximum values. */
diff --git a/bin/warp/ui.c b/bin/warp/ui.c
index 54d8270..10120a2 100644
--- a/bin/warp/ui.c
+++ b/bin/warp/ui.c
@@ -26,9 +26,12 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <errno.h>
 #include <error.h>
 #include <stdio.h>
+#include <string.h>
 
+#include <gnuastro/wcs.h>
 #include <gnuastro/fits.h>
 #include <gnuastro/table.h>
+#include <gnuastro/threads.h>
 #include <gnuastro/linkedlist.h>
 
 #include <timing.h>
@@ -85,13 +88,13 @@ enum program_args_groups
 
 /* Available letters for short options:
 
-   c g i j k l u v w x y
-   A B C E F G H I J L M O Q R T U W X Y Z  */
+   b g i j l n u v w x y
+   A B E F G H I J L M O Q R T U W X Y Z  */
 enum option_keys_enum
 {
   /* With short-option version. */
-  ARGS_OPTION_KEY_KEEPINPUTWCS    = 'n',
-  ARGS_OPTION_KEY_MAXBLANKFRAC    = 'b',
+  ARGS_OPTION_KEY_KEEPWCS         = 'k',
+  ARGS_OPTION_KEY_COVEREDFRAC     = 'C',
   ARGS_OPTION_KEY_TYPE            = 'T',
   ARGS_OPTION_KEY_ALIGN           = 'a',
   ARGS_OPTION_KEY_ROTATE          = 'r',
@@ -101,10 +104,11 @@ enum option_keys_enum
   ARGS_OPTION_KEY_TRANSLATE       = 't',
   ARGS_OPTION_KEY_PROJECT         = 'p',
   ARGS_OPTION_KEY_MATRIX          = 'm',
+  ARGS_OPTION_KEY_CENTERONCORNER  = 'c',
 
   /* Only with long version (start with a value 1000, the rest will be set
      automatically). */
-  ARGS_OPTION_KEY_HSTARTWCS   = 1000,
+  ARGS_OPTION_KEY_HSTARTWCS       = 1000,
   ARGS_OPTION_KEY_HENDWCS,
 };
 
@@ -139,11 +143,13 @@ ui_initialize_options(struct warpparams *p,
 
 
   /* Set the necessary common parameters structure. */
-  cp->poptions           = program_options;
+  cp->program_struct     = p;
   cp->program_name       = PROGRAM_NAME;
   cp->program_exec       = PROGRAM_EXEC;
   cp->program_bibtex     = PROGRAM_BIBTEX;
   cp->program_authors    = PROGRAM_AUTHORS;
+  cp->poptions           = program_options;
+  cp->numthreads         = gal_threads_number();
   cp->coptions           = gal_commonopts_options;
 
 
@@ -151,11 +157,14 @@ ui_initialize_options(struct warpparams *p,
   for(i=0; !gal_options_is_last(&cp->coptions[i]); ++i)
     switch(cp->coptions[i].key)
       {
-      case GAL_OPTIONS_KEY_SEARCHIN:
       case GAL_OPTIONS_KEY_MINMAPSIZE:
-      case GAL_OPTIONS_KEY_TABLEFORMAT:
         cp->coptions[i].mandatory=GAL_OPTIONS_MANDATORY;
         break;
+
+      case GAL_OPTIONS_KEY_SEARCHIN:
+      case GAL_OPTIONS_KEY_TABLEFORMAT:
+        cp->coptions[i].flags=OPTION_HIDDEN;
+        break;
       }
 }
 
@@ -190,10 +199,10 @@ parse_opt(int key, char *arg, struct argp_state *state)
 
     /* Read the non-option tokens (arguments): */
     case ARGP_KEY_ARG:
-      if(p->filename)
+      if(p->inputname)
         argp_error(state, "only one argument (input file) should be given");
       else
-        p->filename=arg;
+        p->inputname=arg;
       break;
 
 
@@ -223,39 +232,232 @@ parse_opt(int key, char *arg, struct argp_state *state)
 
 
 
-
 /**************************************************************/
-/***************       Sanity Check         *******************/
+/**********      Modular matrix linked list       *************/
 /**************************************************************/
-/* Read and check ONLY the options. When arguments are involved, do the
-   check in `ui_check_options_and_arguments'. */
-static void
-ui_read_check_only_options(struct warpparams *p)
+static void *
+ui_add_to_modular_warps_ll(struct argp_option *option, char *arg,
+                           char *filename, size_t lineno, void *params)
 {
+  size_t i, num=0;
+  gal_data_t *new;
+  char *tailptr, *c=arg;
+  double numerator=NAN, denominator=NAN, tmp;
+  struct gal_linkedlist_dll *list=NULL, *tdll;
+  struct warpparams *p=(struct warpparams *)params;
+
+  /* The nature of the arrays/numbers read here is very small, so since
+     `p->cp.minmapsize' might not have been read yet, we will set it to -1
+     (largest size_t number), so the values are kept in memory. */
+  size_t minmapsize=-1;
+
+  /* Parse the (possible) arguments. */
+  if(option->key==ARGS_OPTION_KEY_ALIGN)
+    {
+      /* For functions the standard checking isn't done, so first, we'll
+         make sure that if we are in a configuration file (where
+         `arg!=NULL'), the value is either 0 or 1. */
+      if( arg && strcmp(arg, "0") && strcmp(arg, "1") )
+        error_at_line(EXIT_FAILURE, 0, filename, lineno, "the `--align' "
+                      "option takes no arguments. In a configuration file "
+                      "it can only have the values `1' or `0', indicating "
+                      "if it should be used or not");
+
+      /* Align doesn't take any values, but if called in a configuration
+         file with a value of `0', we should ignore it. */
+      if(arg && *arg=='0') return NULL;
+
+      /* Allocate the data structure. */
+      new=gal_data_alloc(NULL, GAL_DATA_TYPE_FLOAT64, 0, &num, NULL, 0,
+                         minmapsize, NULL, NULL, NULL);
+    }
+  else
+    {
+      /* Go through the input character by character. */
+      while(*c!='\0')
+        {
+        switch(*c)
+          {
+          /* Ignore space or tab. */
+          case ' ':
+          case '\t':
+            ++c;
+            break;
+
+
+          /* Comma marks the transition to the next number. */
+          case ',':
+            if(isnan(numerator))
+              error_at_line(EXIT_FAILURE, 0, filename, lineno, "a number "
+                            "must be given before `,'. You have given: `%s'",
+                            arg);
+            gal_linkedlist_add_to_dll(&list, isnan(denominator)
+                                      ? numerator : numerator/denominator);
+            numerator=denominator=NAN;
+            ++num;
+            ++c;
+            break;
+
+
+          /* Divide two numbers. */
+          case '/':
+            if( isnan(numerator) || !isnan(denominator) )
+              error_at_line(EXIT_FAILURE, 0, filename, lineno, "`/' must "
+                            "only be between two numbers and used for "
+                            "division. But you have given `%s'. This "
+                            "was a value to the `%s' option", arg,
+                            option->name);
+            ++c;
+            break;
+
+
+          /* Read the number. */
+          default:
+
+            /* Parse the string. */
+            tmp=strtod(c, &tailptr);
+            if(tailptr==c)
+              error_at_line(EXIT_FAILURE, 0, filename, lineno, "the first "
+                            "part of `%s' couldn't be read as a number. This "
+                            "was part of `%s' (value to the `%s' option)", c,
+                            arg, option->name);
+
+            /* See if the number should be put in the numerator or
+               denominator. */
+            if(isnan(numerator)) numerator=tmp;
+            else
+              {
+                if(isnan(denominator)) denominator=tmp;
+                else error_at_line(EXIT_FAILURE, 0, filename, lineno, "more "
+                                "than two numbers in each element.");
+              }
+
+            /* Set `c' to tailptr. */
+            c=tailptr;
+          }
+        }
 
-  /* Check if the format of the output table is valid, given the type of
-     the output. */
-  gal_table_check_fits_format(p->cp.output, p->cp.tableformat);
+      /* If the last number, wasn't finished by a `,', add the read value
+         to the list */
+      if( !isnan(numerator) )
+        {
+          ++num;
+          gal_linkedlist_add_to_dll(&list, isnan(denominator)
+                                    ? numerator : numerator/denominator);
+        }
+
+      /* Allocate the new data structure and fill it up. */
+      i=num;
+      new=gal_data_alloc(NULL, GAL_DATA_TYPE_FLOAT64, 1, &num, NULL, 0,
+                         minmapsize, NULL, NULL, NULL);
+      for(tdll=list;tdll!=NULL;tdll=tdll->next)
+        ((double *)new->array)[--i]=tdll->v;
+      gal_linkedlist_free_dll(list);
+    }
 
+  /* For a check.
+  printf("%s (%s): %zu number(s)\n", option->name, arg, num);
+  for(i=0;i<num;++i)
+    printf("\t%.15f\n", ((double *)new->array)[i]);
+  */
+
+  /* If this was a matrix, then put it in the matrix element of the main
+     data structure. Otherwise, add the list of given values to the modular
+     warpings list. */
+  if(option->key==ARGS_OPTION_KEY_MATRIX)
+    {
+      /* Some sanity checks. */
+      if(p->matrix)
+        error_at_line(EXIT_FAILURE, 0, filename, lineno, "only one matrix "
+                      "may be given, you can use multiple modular warpings");
+      if(num!=4 && num!=9)
+        error_at_line(EXIT_FAILURE, 0, filename, lineno, "only a 4 or 9 "
+                      "element `matrix' is currently acceptable. `%s' has "
+                      "%zu elements", arg, num);
+
+      /* Keep the matrix in the main structure. */
+      p->matrix=new;
+    }
+  else
+    {
+      /* No more than two numbers should be given for the modular
+         warpings. */
+      if(new->size>2)
+        error_at_line(EXIT_FAILURE, 0, filename, lineno, "%zu numbers "
+                      "given to the `%s' option. Modular warpings can "
+                      "accept 2 numbers at the most currently (for 2D "
+                      "datasets)", new->size, option->name);
+
+      /* Some modular-warp specific sanity checks: rotate only needs one
+         number, and flip's values should only be 0 and 1. */
+      if(option->key==ARGS_OPTION_KEY_ROTATE)
+        {
+          if(new->size!=1)
+            error_at_line(EXIT_FAILURE, 0, filename, lineno, "the `rotate' "
+                      "option only takes one value (the angle of rotation). "
+                      "You have given: `%s'", arg);
+        }
+      else if (option->key==ARGS_OPTION_KEY_FLIP)
+        {
+          for(i=0;i<new->size;++i)
+            {
+              tmp=((double *)(new->array))[i];
+              if(tmp!=0.0f && tmp!=1.0f)
+                error_at_line(EXIT_FAILURE, 0, filename, lineno, "`flip' "
+                              "only takes values of `1' and `0'. You have "
+                              "given `%s'", arg);
+            }
+        }
+
+      /* Keep the final value. */
+      new->status=option->key;
+      new->next=p->modularll;
+      p->modularll=new;
+    }
+  return NULL;
 }
 
 
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**************************************************************/
+/***************       Sanity Check         *******************/
+/**************************************************************/
 static void
 ui_check_options_and_arguments(struct warpparams *p)
 {
-  /* Make sure an input file name was given and if it was a FITS file, that
-     a HDU is also given. */
-  if(p->filename)
+  /* Read the input.*/
+  if(p->inputname)
     {
-      if( gal_fits_name_is_fits(p->filename) && p->cp.hdu==NULL )
-        error(EXIT_FAILURE, 0, "no HDU specified. When the input is a FITS "
-              "file, a HDU must also be specified, you can use the `--hdu' "
+      /* Make sure a HDU is given. */
+      if( gal_fits_name_is_fits(p->inputname) && p->cp.hdu==NULL )
+        error(EXIT_FAILURE, 0, "no HDU specified, you can use the `--hdu' "
               "(`-h') option and give it the HDU number (starting from "
-              "zero), extension name, or anything acceptable by CFITSIO");
-
+              "zero), or extension name (generally, anything acceptable "
+              "by CFITSIO)");
+
+      /* Read the input image as double type and its WCS structure. */
+      p->input=gal_fits_img_read_to_type(p->inputname, p->cp.hdu,
+                                         GAL_DATA_TYPE_FLOAT64,
+                                         p->cp.minmapsize);
+      gal_wcs_read(p->inputname, p->cp.hdu, p->hstartwcs,
+                   p->hendwcs, &p->input->nwcs, &p->input->wcs);
     }
   else
     error(EXIT_FAILURE, 0, "no input file is specified");
@@ -281,86 +483,502 @@ ui_check_options_and_arguments(struct warpparams *p)
 
 
 /**************************************************************/
-/***************       Preparations         *******************/
+/***************     Matrix preparations     ******************/
 /**************************************************************/
-void
-ui_preparations(struct warpparams *p)
+static void
+ui_error_no_warps()
 {
-  char *numstr;
-  int tableformat;
-  gal_data_t *allcols;
-  size_t i, numcols, numrows;
-  struct gal_options_common_params *cp=&p->cp;
+  error(EXIT_FAILURE, 0, "no warping specified, you can either use the "
+        "`--matrix' option for any low-level warp, or specify multipole "
+        "modular warpings with options like `--rotate', `--scale' and etc. "
+        "You can see the full list with the `--help' option");
+}
 
-  /* If there were no columns specified, we want the full set of
-     columns. */
-  if(p->columns==NULL)
+
+
+
+
+/* This function is mainly for easy checking/debugging. */
+static void
+ui_matrix_print(double *matrix)
+{
+  printf("%-10.3f%-10.3f%-10.3f\n", matrix[0], matrix[1], matrix[2]);
+  printf("%-10.3f%-10.3f%-10.3f\n", matrix[3], matrix[4], matrix[5]);
+  printf("%-10.3f%-10.3f%-10.3f\n", matrix[6], matrix[7], matrix[8]);
+}
+
+
+
+
+
+static void
+ui_matrix_prepare_raw(struct warpparams *p)
+{
+  size_t *dsize;
+  double *in=p->matrix->array, *final;
+
+  /* If the matrix was 2D, then convert it to 3D. Note that we done a size
+     check when reading the matrix, so at this point, it either has 9
+     elements, or 4. */
+  if(p->matrix->size==4)
     {
-      /* Read the table information for the number of columns and rows. */
-      allcols=gal_table_info(p->filename, cp->hdu, &numcols,
-                             &numrows, &tableformat);
+      /* Allocate the final matrix. */
+      final=gal_data_malloc_array(GAL_DATA_TYPE_FLOAT64, 9);
+
+      /* Fill in the final 3x3 matrix from the 2x2 matrix. */
+      final[0]=in[0];    final[1]=in[1];   final[2]=0.0f;
+      final[3]=in[2];    final[4]=in[3];   final[5]=0.0f;
+      final[6]=0.0f;     final[7]=0.0f;    final[8]=1.0f;
+
+      /* Free the old matrix array and put in the new one. */
+      free(p->matrix->array);
+      p->matrix->size=9;
+      p->matrix->array=final;
+    }
 
-      /* If there was no actual data in the file, then inform the user */
-      if(allcols==NULL)
-        error(EXIT_FAILURE, 0, "%s: no usable data rows", p->filename);
+  /* Correct the dimensional information, because the matrix was read as a
+     single dimensional list of numbers. */
+  free(p->matrix->dsize);
+  dsize=p->matrix->dsize=gal_data_malloc_array(GAL_DATA_TYPE_SIZE_T, 2);
+  dsize[0]=dsize[1]=3;
+  p->matrix->ndim=2;
+}
 
 
-      /* If the user just wanted information, then print it. */
-      if(p->information)
-        {
-          /* Print the file information. */
-          printf("--------\n");
-          printf("%s", p->filename);
-          if(gal_fits_name_is_fits(p->filename))
-            printf(" (hdu: %s)\n", cp->hdu);
-          else
-            printf("\n");
-
-          /* Print each column's information. */
-          gal_table_print_info(allcols, numcols, numrows);
-        }
 
 
-      /* Free the information from all the columns. */
-      for(i=0;i<numcols;++i)
-        gal_data_free_contents(&allcols[i]);
-      free(allcols);
 
+/* Set the matrix so the image is aligned with the axises. Note that
+   WCSLIB automatically fills the CRPI */
+static void
+ui_matrix_make_align(struct warpparams *p, double *tmatrix)
+{
+  double A, *w, *ps, amatrix[4];
+
+  /* Make sure the input image had a WCS structure. */
+  if(p->input->wcs==NULL)
+    error(EXIT_FAILURE, 0, "%s (hdu: %s): no WCS information present, "
+          "hence the `--align' option cannot be used", p->inputname,
+          p->cp.hdu);
+
+  /* Check if there is only two WCS axises: */
+  if(p->input->wcs->naxis!=2)
+    error(EXIT_FAILURE, 0, "the WCS structure of %s (hdu: %s) has %d "
+          "axises. For the `--align' option to operate it must be 2",
+          p->inputname, p->cp.hdu, p->input->wcs->naxis);
+
+
+  /* Find the pixel scale along the two dimensions. Note that we will be
+     using the scale along the image X axis for both values. */
+  w=gal_wcs_array_from_wcsprm(p->input->wcs);
+  ps=gal_wcs_pixel_scale_deg(p->input->wcs);
+
+
+  /* Lets call the given WCS orientation `W', the rotation matrix we want
+     to find as `X' and the final (aligned matrix) to have just one useful
+     value: `a' (which is the pixel scale):
+
+        x0  x1       w0  w1      -a  0
+        x2  x3   *   w2  w3   =   0  a
+
+     Let's open up the matrix multiplication, so we can find the `X'
+     elements as function of the `W' elements and `a'.
+
+        x0*w0 + x1*w2 = -a                                         (1)
+        x0*w1 + x1*w3 =  0                                         (2)
+        x2*w0 + x3*w2 =  0                                         (3)
+        x2*w1 + x3*w3 =  a                                         (4)
+
+     Let's bring the X with the smaller index in each equation to the left
+     side:
 
-      /* If the user just wanted information, then free the allocated
-         spaces and exit. Otherwise, add the number of columns to the list
-         if the user wanted to print the columns (didn't just want their
-         information. */
-      if(p->information)
+        x0 = (-w2/w0)*x1 - a/w0                                    (5)
+        x0 = (-w3/w1)*x1                                           (6)
+        x2 = (-w2/w0)*x3                                           (7)
+        x2 = (-w3/w1)*x3 + a/w1                                    (8)
+
+    Using (5) and (6) we can find x0 and x1, by first eliminating x0:
+
+       (-w2/w0)*x1 - a/w0 = (-w3/w1)*x1 -> (w3/w1 - w2/w0) * x1 = a/w0
+
+    For easy reading/writing, let's define: A = (w3/w1 - w2/w0)
+
+       --> x1 = a / w0 / A
+       --> x0 = -1 * x1 * w3 / w1
+
+    Similar to the above, we can find x2 and x3 from (7) and (8):
+
+       (-w2/w0)*x3 = (-w3/w1)*x3 + a/w1 -> (w3/w1 - w2/w0) * x3 = a/w1
+
+       --> x3 = a / w1 / A
+       --> x2 = -1 * x3 * w2 / w0
+
+    Note that when the image is already aligned, a unity matrix should be
+    output.
+   */
+  if( w[1]==0.0f && w[2]==0.0f )
+    {
+      amatrix[0]=1.0f;   amatrix[1]=0.0f;
+      amatrix[2]=0.0f;   amatrix[3]=1.0f;
+    }
+  else
+    {
+      A = (w[3]/w[1]) - (w[2]/w[0]);
+      amatrix[1] = ps[0] / w[0] / A;
+      amatrix[3] = ps[0] / w[1] / A;
+      amatrix[0] = -1 * amatrix[1] * w[3] / w[1];
+      amatrix[2] = -1 * amatrix[3] * w[2] / w[0];
+    }
+
+
+  /* For a check:
+  printf("ps: %e\n", ps);
+  printf("w:\n");
+  printf("  %.8e    %.8e\n", w[0], w[1]);
+  printf("  %.8e    %.8e\n", w[2], w[3]);
+  printf("x:\n");
+  printf("  %.8e    %.8e\n", amatrix[0], amatrix[1]);
+  printf("  %.8e    %.8e\n", amatrix[2], amatrix[3]);
+  exit(0);
+  */
+
+  /* Put the matrix elements into the output array: */
+  tmatrix[0]=amatrix[0];  tmatrix[1]=amatrix[1]; tmatrix[2]=0.0f;
+  tmatrix[3]=amatrix[2];  tmatrix[4]=amatrix[3]; tmatrix[5]=0.0f;
+  tmatrix[6]=0.0f;        tmatrix[7]=0.0f;       tmatrix[8]=1.0f;
+
+  /* Clean up. */
+  free(w);
+  free(ps);
+}
+
+
+
+
+
+static void
+ui_matrix_inplacw_multiply(double *in, double *with)
+{
+  /* `tin' will keep the values of the input array because we want to
+     write the multiplication result in the input array. */
+  double tin[9]={in[0],in[1],in[2],in[3],in[4],in[5],in[6],in[7],in[8]};
+
+  /* For easy checking, here are the matrix/memory layouts:
+          tin[0] tin[1] tin[2]     with[0] with[1] with[2]
+          tin[3] tin[4] tin[5]  *  with[3] with[4] with[5]
+          tin[6] tin[7] tin[8]     with[6] with[7] with[8]   */
+  in[0] = tin[0]*with[0] + tin[1]*with[3] + tin[2]*with[6];
+  in[1] = tin[0]*with[1] + tin[1]*with[4] + tin[2]*with[7];
+  in[2] = tin[0]*with[2] + tin[1]*with[5] + tin[2]*with[8];
+
+  in[3] = tin[3]*with[0] + tin[4]*with[3] + tin[5]*with[6];
+  in[4] = tin[3]*with[1] + tin[4]*with[4] + tin[5]*with[7];
+  in[5] = tin[3]*with[2] + tin[4]*with[5] + tin[5]*with[8];
+
+  in[6] = tin[6]*with[0] + tin[7]*with[3] + tin[8]*with[6];
+  in[7] = tin[6]*with[1] + tin[7]*with[4] + tin[8]*with[7];
+  in[8] = tin[6]*with[2] + tin[7]*with[5] + tin[8]*with[8];
+}
+
+
+
+
+
+
+static void
+ui_matrix_from_modular(struct warpparams *p)
+{
+  gal_data_t *pop;
+  size_t dsize[]={3,3};
+  double s, c, v1, v2, *final, module[9];
+
+  /* Reverse the list of modular warpings to be in the same order as the
+     user specified.*/
+  gal_data_reverse_ll(&p->modularll);
+
+  /* Allocate space for the final matrix. */
+  p->matrix=gal_data_alloc(NULL, GAL_DATA_TYPE_FLOAT64, 2, dsize, NULL, 0,
+                           p->cp.minmapsize, NULL, NULL, NULL);
+  final=p->matrix->array;
+
+  /* Fill in the final matrix to start with. */
+  final[0]=1.0f;     final[1]=0.0f;     final[2]=0.0f;
+  final[3]=0.0f;     final[4]=1.0f;     final[5]=0.0f;
+  final[6]=0.0f;     final[7]=0.0f;     final[8]=1.0f;
+
+  /* Apply all modular warps. */
+  while(p->modularll)
+    {
+      /* Pop the top element. */
+      pop=gal_data_pop_from_ll(&p->modularll);
+
+      /* Set the (possibly) two values given for this warp. */
+      v1 = pop->ndim   ? ((double *)(pop->array))[0] : 0.0f;
+      v2 = pop->size>1 ? ((double *)(pop->array))[1] : v1;
+
+      /* Depending on the type of the modular warp do it. Recall that the
+         code for the warp, was stored in the `status' element of the data
+         structure.*/
+      switch(pop->status)
         {
-          ui_free_report(p);
-          exit(EXIT_SUCCESS);
+        case ARGS_OPTION_KEY_ALIGN:
+          ui_matrix_make_align(p, module);
+          break;
+
+        case ARGS_OPTION_KEY_ROTATE:
+          s = sin( v1 * M_PI / 180 );
+          c = cos( v1 * M_PI / 180 );
+          module[0]=c;          module[1]=s;      module[2]=0.0f;
+          module[3]=-1.0f*s;    module[4]=c;      module[5]=0.0f;
+          module[6]=0.0f;       module[7]=0.0f;   module[8]=1.0f;
+          break;
+
+        case ARGS_OPTION_KEY_SCALE:
+          module[0]=v1;         module[1]=0.0f;   module[2]=0.0f;
+          module[3]=0.0f;       module[4]=v2;     module[5]=0.0f;
+          module[6]=0.0f;       module[7]=0.0f;   module[8]=1.0f;
+          break;
+
+        case ARGS_OPTION_KEY_FLIP:
+          if      ( v1==1.0f && v2==0.0f )
+            {
+              module[0]=1.0f;   module[1]=0.0f;
+              module[3]=0.0f;   module[4]=-1.0f;
+            }
+          else if ( v1==0.0f && v2==1.0f )
+            {
+              module[0]=-1.0f;  module[1]=0.0f;
+              module[3]=0.0f;   module[4]=1.0f;
+            }
+          else if ( v1==1.0f && v2==1.0f )
+            {
+              module[0]=-1.0f;  module[1]=0.0f;
+              module[3]=0.0f;   module[4]=-1.0f;
+            }
+          else                  /* When both are zero, just in case! */
+            {
+              module[0]=1.0f;   module[1]=0.0f;
+              module[3]=0.0f;   module[4]=1.0f;
+            }
+                                                  module[2]=0.0f;
+                                                  module[5]=0.0f;
+          module[6]=0.0f;       module[7]=0.0f;   module[8]=1.0f;
+          break;
+
+        case ARGS_OPTION_KEY_SHEAR:
+          module[0]=1.0f;       module[1]=v1;     module[2]=0.0f;
+          module[3]=v2;         module[4]=1.0f;   module[5]=0.0f;
+          module[6]=0.0f;       module[7]=0.0f;   module[8]=1.0f;
+          break;
+
+        case ARGS_OPTION_KEY_TRANSLATE:
+          module[0]=1.0f;       module[1]=0.0f;     module[2]=v1;
+          module[3]=0.0f;       module[4]=1.0f;     module[5]=v2;
+          module[6]=0.0f;       module[7]=0.0f;     module[8]=1.0f;
+          break;
+
+        case ARGS_OPTION_KEY_PROJECT:
+          module[0]=1.0f;       module[1]=0.0f;     module[2]=0.0f;
+          module[3]=0.0f;       module[4]=1.0f;     module[5]=0.0f;
+          module[6]=v1;         module[7]=v2;       module[8]=1.0f;
+          break;
+
+        default:
+          error(EXIT_FAILURE, 0, "a bug! the code %d is not recognized as "
+                "a valid modular warp in `ui_matrix_from_modular', this is "
+                "not your fault, something in the programming has gone "
+                "wrong. Please contact us at %s so we can correct it",
+                pop->status, PACKAGE_BUGREPORT);
         }
-      else
-        for(i=1;i<=numcols;++i)
-          {
-            asprintf(&numstr, "%zu", i);
-            gal_linkedlist_add_to_stll(&p->columns, numstr, 0);
-          }
+
+      /* Multiply the main matrix with this modular matrix. */
+      ui_matrix_inplacw_multiply(p->matrix->array, module);
+
+      /* Clean up. */
+      gal_data_free(pop);
     }
+}
+
+
+
+
+
+static void
+ui_matrix_center_on_corner(struct warpparams *p)
+{
+  double *b, *d, *df;
+  double before[9]={1,0,0.5,0,1,0.5,0,0,1};
+  double after[9]={1,0,-0.5,0,1,-0.5,0,0,1};
+
+  /* Shift the matrix by +0.5 so the coordinate center lies at the bottom
+     left corner of the first pixel. Note that the updated values are
+     written into the first argument of the function.*/
+  ui_matrix_inplacw_multiply(before, p->matrix->array);
+
+  /* Translate them back into the proper FITS center. */
+  ui_matrix_inplacw_multiply(before, after);
+
+  /* The final matrix is in `before', so put its values into the output
+     matrix. */
+  b = before;
+  df = (d=p->matrix->array) + p->matrix->size;
+  do *d=*b++; while(++d<df);
+}
+
+
+
+
+
+static void
+ui_matrix_finalize(struct warpparams *p)
+{
+  double *d, *df, *inv;
+
+  /* If a matrix string is not given, the use the modular warpings. */
+  if(p->matrix)
+    ui_matrix_prepare_raw(p);
+  else if (p->modularll)
+    ui_matrix_from_modular(p);
+  else
+    ui_error_no_warps();
+
+  /* If the user has asked for it, set the coordinate center on the corner
+     of the first pixel. */
+  if(p->centeroncorner) ui_matrix_center_on_corner(p);
+
+  /* Check if there are any non-normal numbers in the matrix: */
+  df=(d=p->matrix->array)+p->matrix->size;
+  do
+    if(!isfinite(*d++))
+      {
+        ui_matrix_print(p->matrix->array);
+        error(EXIT_FAILURE, 0, "%f is not a `normal' number in the "
+              "input matrix shown above", *(d-1));
+      }
+  while(d<df);
+
+  /* Check if the determinant is not zero: */
+  d=p->matrix->array;
+  if( d[0]*d[4]*d[8] + d[1]*d[5]*d[6] + d[2]*d[3]*d[7]
+      - d[2]*d[4]*d[6] - d[1]*d[3]*d[8] - d[0]*d[5]*d[7] == 0 )
+    error(EXIT_FAILURE, 0, "the determinant of the given matrix "
+          "is zero");
+
+  /* Check if the transformation is spatially invariant, in other words, if
+     it differs between differet regions of the output. If it doesn't we
+     can use this information for a more efficient processing. This is not
+     yet implemented. */
+
+   /* Make the inverse matrix: */
+  inv=p->inverse=gal_data_malloc_array(GAL_DATA_TYPE_FLOAT64, 9);
+  inv[0] = d[4]*d[8] - d[5]*d[7];
+  inv[1] = d[2]*d[7] - d[1]*d[8];
+  inv[2] = d[1]*d[5] - d[2]*d[4];
+  inv[3] = d[5]*d[6] - d[3]*d[8];
+  inv[4] = d[0]*d[8] - d[2]*d[6];
+  inv[5] = d[2]*d[3] - d[0]*d[5];
+  inv[6] = d[3]*d[7] - d[4]*d[6];
+  inv[7] = d[1]*d[6] - d[0]*d[7];
+  inv[8] = d[0]*d[4] - d[1]*d[3];
+  /* Just for a test:
+  {
+    size_t i;
+    printf("\nInput matrix:");
+    for(i=0;i<9;++i) { if(i%3==0) printf("\n"); printf("%-10.5f", d[i]); }
+    printf("\n-----------\n");
+    printf("Inverse matrix:");
+    for(i=0;i<9;++i) { if(i%3==0) printf("\n"); printf("%-10.5f", inv[i]); }
+    printf("\n\n");
+  }
+  */
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**************************************************************/
+/************        General preparations      ****************/
+/**************************************************************/
+/* When only one transformation is required, set the suffix for automatic
+   output to more meaningful string. */
+char *
+ui_set_suffix(struct warpparams *p)
+{
+  /* A small independent sanity check: we either need a matrix or at least
+     one modular warping. */
+  if(p->matrix==NULL && p->modularll==NULL) ui_error_no_warps();
+
+  /* We only want the more meaningful suffix when the list is defined AND
+     when its only has one node (the `next' element is NULL). */
+  if(p->matrix==NULL && p->modularll->next==NULL)
+    switch(p->modularll->status)
+      {
+      case ARGS_OPTION_KEY_ALIGN:
+        return "_aligned.fits";
 
-  /* Reverse the list of column search criteria that we are looking for
-     (since this is a last-in-first-out linked list, the order that
-     elements were added to the list is the reverse of the order that they
-     will be popped). */
-  gal_linkedlist_reverse_stll(&p->columns);
-  p->table=gal_table_read(p->filename, cp->hdu, p->columns, cp->searchin,
-                          cp->ignorecase, cp->minmapsize);
-
-  /* If there was no actual data in the file, then inform the user and
-     abort. */
-  if(p->table==NULL)
-    error(EXIT_FAILURE, 0, "%s: no usable data rows (non-commented and "
-          "non-blank lines)", p->filename);
-
-  /* Now that the data columns are ready, we can free the string linked
-     list. */
-  gal_linkedlist_free_stll(p->columns, 1);
+      case ARGS_OPTION_KEY_ROTATE:
+        return "_rotated.fits";
+
+      case ARGS_OPTION_KEY_SCALE:
+        return "_scaled.fits";
+
+      case ARGS_OPTION_KEY_FLIP:
+        return "_flipped.fits";
+
+      case ARGS_OPTION_KEY_SHEAR:
+        return "_sheared.fits";
+
+      case ARGS_OPTION_KEY_TRANSLATE:
+        return "_translated.fits";
+
+      case ARGS_OPTION_KEY_PROJECT:
+        return "_projected.fits";
+
+      default:
+        error(EXIT_FAILURE, 0, "a bug! please contact us at %s so we can "
+              "fix the problem. The modular warp code %d is not recognized "
+              "in `ui_set_suffix'", PACKAGE_BUGREPORT, p->modularll->status);
+        return NULL;
+      }
+  else
+    return "_warped.fits";
+}
+
+
+
+
+
+static void
+ui_preparations(struct warpparams *p)
+{
+  /* Set the output name. This needs to be done before `ui_finalize_matrix'
+     because that function will free the linked list of modular warpings
+     which we will need to determine the suffix if no output name is
+     specified. */
+  if(p->cp.output)
+    gal_checkset_check_remove_file(p->cp.output, p->cp.dontdelete);
+  else
+    p->cp.output=gal_checkset_automatic_output(&p->cp, p->inputname,
+                                               ui_set_suffix(p));
+
+  /* Prepare the final warping matrix. */
+  ui_matrix_finalize(p);
 }
 
 
@@ -416,11 +1034,6 @@ ui_read_check_inputs_setup(int argc, char *argv[], struct 
warpparams *p)
   gal_options_read_config_set(&p->cp);
 
 
-  /* Read the options into the program's structure, and check them and
-     their relations prior to printing. */
-  ui_read_check_only_options(p);
-
-
   /* Print the option values if asked. Note that this needs to be done
      after the option checks so un-sane values are not printed in the
      output state. */
@@ -435,6 +1048,24 @@ ui_read_check_inputs_setup(int argc, char *argv[], struct 
warpparams *p)
 
   /* Read/allocate all the necessary starting arrays. */
   ui_preparations(p);
+
+
+  /* Everything is ready, notify the user of the program starting. */
+  if(!p->cp.quiet)
+    {
+      double *matrix=p->matrix->array;
+      printf(PROGRAM_NAME" started on %s", ctime(&p->rawtime));
+      printf(" Using %zu CPU thread%s\n", p->cp.numthreads,
+             p->cp.numthreads==1 ? "." : "s.");
+      printf(" Input: %s (hdu: %s)\n", p->inputname, p->cp.hdu);
+      printf(" matrix:"
+             "\n\t%.4f   %.4f   %.4f"
+             "\n\t%.4f   %.4f   %.4f"
+             "\n\t%.4f   %.4f   %.4f\n",
+             matrix[0], matrix[1], matrix[2],
+             matrix[3], matrix[4], matrix[5],
+             matrix[6], matrix[7], matrix[8]);
+    }
 }
 
 
@@ -460,12 +1091,11 @@ ui_read_check_inputs_setup(int argc, char *argv[], 
struct warpparams *p)
 /************      Free allocated, report         *************/
 /**************************************************************/
 void
-ui_free_report(struct warpparams *p)
+ui_free_report(struct warpparams *p, struct timeval *t1)
 {
   /* Free the allocated arrays: */
   free(p->cp.hdu);
   free(p->cp.output);
-  free(p->cp.searchinstr);
-  free(p->cp.tableformatstr);
-  gal_data_free_ll(p->table);
+  gal_data_free(p->input);
+  gal_data_free(p->matrix);
 }
diff --git a/bin/warp/ui.h b/bin/warp/ui.h
index 193a118..39e37c3 100644
--- a/bin/warp/ui.h
+++ b/bin/warp/ui.h
@@ -23,8 +23,9 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #ifndef UI_H
 #define UI_H
 
+/* Functions */
 void
-ui_read_check_inputs_setup(int argc, char *argv[], struct imgwaprparams *p);
+ui_read_check_inputs_setup(int argc, char *argv[], struct warpparams *p);
 
 void
 ui_free_report(struct warpparams *p, struct timeval *t1);
diff --git a/bin/warp/warp.c b/bin/warp/warp.c
index cea91f4..a639189 100644
--- a/bin/warp/warp.c
+++ b/bin/warp/warp.c
@@ -117,19 +117,19 @@ warponthread(void *inparam)
   struct iwpparams *iwp=(struct iwpparams*)inparam;
   struct warpparams *p=iwp->p;
 
-  long is0=p->is0, is1=p->is1;
-  double area, nanarea, *input=p->input, v=NAN;
   size_t *extinds=p->extinds, *ordinds=p->ordinds;
-  size_t i, j, ind, os1=p->onaxes[0], numcrn, numinput;
-  double ocrn[8], icrn_base[8], icrn[8], *output=p->output;
+  long is0=p->input->dsize[0], is1=p->input->dsize[1];
+  double area, filledarea, *input=p->input->array, v=NAN;
+  size_t i, j, ind, os1=p->output->dsize[1], numcrn, numinput;
   long x, y, xstart, xend, ystart, yend; /* Might be negative */
+  double ocrn[8], icrn_base[8], icrn[8], *output=p->output->array;
   double pcrn[8], *outfpixval=p->outfpixval, ccrn[GAL_POLYGON_MAX_CORNERS];
 
   for(i=0;(ind=iwp->indexs[i])!=GAL_THREADS_NON_THRD_INDEX;++i)
     {
       /* Initialize the output pixel value: */
       numinput=0;
-      output[ind]=nanarea=0.0f;
+      output[ind]=filledarea=0.0f;
 
       /* Set the corners of this output pixel. The ind/os1 and ind%os1
          start from 0. Note that the outfpixval already contains the
@@ -205,11 +205,10 @@ warponthread(void *inparam)
                  output pixel covers a NaN pixel in the input grid,
                  then calculate the area of this NaN pixel to account
                  for it later. */
-              if( isnan(v) )
-                nanarea+=area;
-              else
+              if( !isnan(v) )
                 {
                   ++numinput;
+                  filledarea+=area;
                   output[ind]+=v*area;
                 }
 
@@ -241,29 +240,13 @@ warponthread(void *inparam)
             }
         }
 
-      /* Correct for the area covered by a NaN. The basic idea is
-         this: The full pixel (with area `A') would have a value of
-         `F'. But we have only measured the value `f' over the area
-         `a', so a simple linear extrapolation would give: F=fA/a. */
-      if(numinput && nanarea!=0.0f)
-        {
-          /* For a check:
-          printf("%zu: %f/%f --> %f\n", ind, nanarea, p->opixarea,
-                 nanarea/p->opixarea);
-          */
-
-          if(nanarea/p->opixarea<p->maxblankfrac)
-            output[ind]*=p->opixarea/(p->opixarea-nanarea);
-          else
-            numinput=0;
-        }
+      /* See if the pixel value should be set to NaN or not (because of not
+         enough coverage). */
+      if(numinput && filledarea/p->opixarea < p->coveredfrac-1e-5)
+        numinput=0;
 
       /* Write the final value to disk: */
-      if(numinput==0 && p->zerofornoinput==0)
-        {
-          output[ind]=NAN;
-          ++p->numnul;
-        }
+      if(numinput==0) output[ind]=NAN;
     }
 
 
@@ -309,22 +292,24 @@ warponthread(void *inparam)
    the image altough the scale might change.
 */
 void
-warppreparations(struct imgwarpparams *p)
+warppreparations(struct warpparams *p)
 {
+  double is0=p->input->dsize[0], is1=p->input->dsize[1];
+
   double output[8], forarea[8];
   double icrn[8]={0,0,0,0,0,0,0,0};
-  size_t i, *extinds=p->extinds, size;
+  size_t i, *extinds=p->extinds, dsize[2];
   double xmin=DBL_MAX, xmax=-DBL_MAX, ymin=DBL_MAX, ymax=-DBL_MAX;
   double ocrn[8]={0.5f,0.5f,  1.5f,0.5f, 0.5f,1.5f,   1.5f, 1.5f};
-  double input[8]={0.5f,0.5f,             p->is1+0.5f, 0.5f,
-                   0.5f, p->is0+0.5f,     p->is1+0.5f, p->is0+0.5f};
+  double input[8]={ 0.5f, 0.5f,         is1+0.5f, 0.5f,
+                    0.5f, is0+0.5f,     is1+0.5f, is0+0.5f };
 
   /* Find the range of pixels of the input image. All the input
      positions are moved to the negative by half a pixel since the
      center of the pixel is an integer value.*/
   for(i=0;i<4;++i)
     {
-      mappoint(&input[i*2], p->matrix, &output[i*2]);
+      mappoint(&input[i*2], (double *)(p->matrix->array), &output[i*2]);
       if(output[i*2]<xmin)     xmin = output[i*2];
       if(output[i*2]>xmax)     xmax = output[i*2];
       if(output[i*2+1]<ymin)   ymin = output[i*2+1];
@@ -344,25 +329,23 @@ warppreparations(struct imgwarpparams *p)
      the maximums is that these points are the farthest extremes of
      the input image. If they are half a pixel value, they should
      point to the pixel before. */
-  p->onaxes[0]=nearestint_halflower(xmax)-nearestint_halfhigher(xmin)+1;
-  p->onaxes[1]=nearestint_halflower(ymax)-nearestint_halfhigher(ymin)+1;
+  dsize[1]=nearestint_halflower(xmax)-nearestint_halfhigher(xmin)+1;
+  dsize[0]=nearestint_halflower(ymax)-nearestint_halfhigher(ymin)+1;
   p->outfpixval[0]=nearestint_halfhigher(xmin);
   p->outfpixval[1]=nearestint_halfhigher(ymin);
   /* For a check:
   printf("Wrapped:\n");
-  printf("onaxes: (%zu, %zu)\n", p->onaxes[0], p->onaxes[1]);
-  printf("outfpixval=(%.4f, %.4f)\n", p->outfpixval[0], p->outfpixval[1]);
+  printf("dsize [C]: (%zu, %zu)\n", dsize[0], dsize[1]);
+  printf("outfpixval [FITS]: (%.4f, %.4f)\n", p->outfpixval[0],
+         p->outfpixval[1]);
   */
 
   /* We now know the size of the output and the starting and ending
      coordinates in the output image (bottom left corners of pixels)
      for the transformation. */
-  errno=0;
-  size=p->onaxes[0]*p->onaxes[1];
-  p->output=malloc(size*sizeof *p->output);
-  if(p->output==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for the output array",
-          size*sizeof *p->output);
+  p->output=gal_data_alloc(NULL, GAL_DATA_TYPE_FLOAT64, 2, dsize,
+                           p->input->wcs, 0, p->cp.minmapsize, "Warped",
+                           p->input->unit, NULL);
 
 
   /* Order the corners of the inverse-transformed pixel (from the
@@ -426,19 +409,19 @@ warppreparations(struct imgwarpparams *p)
    converted from homogeneous coordinates). Then Multiply the crpix
    array with the ACTUAL transformation matrix. */
 void
-correctwcssaveoutput(struct warpparams *p)
+correct_wcs_save_output(struct warpparams *p)
 {
   size_t i;
-  void *array;
-  double *pixelscale;
-  double *m=p->matrix, diff;
+  double *m=p->matrix->array, diff;
   char keyword[9*FLEN_KEYWORD];
+  struct wcsprm *wcs=p->output->wcs;
   struct gal_fits_key_ll *headers=NULL;
-  double tpc[4], tcrpix[3], *crpix=p->wcs->crpix, *pc=p->wcs->pc;
+  double tpc[4], tcrpix[3], *pixelscale;
+  double *crpix=wcs->crpix, *pc=wcs->pc;
   double tinv[4]={p->inverse[0]/p->inverse[8], p->inverse[1]/p->inverse[8],
                   p->inverse[3]/p->inverse[8], p->inverse[4]/p->inverse[8]};
 
-  if(p->correctwcs && p->wcs)
+  if(p->keepwcs==0 && wcs)
     {
       /* Correct the PC matrix: */
       tpc[0]=pc[0]*tinv[0]+pc[1]*tinv[2];
@@ -456,50 +439,35 @@ correctwcssaveoutput(struct warpparams *p)
       crpix[1]=tcrpix[1]/tcrpix[2]-p->outfpixval[1]+1;
     }
 
-
-  /* Convert the output to the input image format: */
-  if(p->inputbitpix==DOUBLE_IMG || p->doubletype)
-    {
-      array=p->output;
-      p->inputbitpix=DOUBLE_IMG; /* Not converted and p->doubletype==1 */
-    }
-  else
-    gal_fits_change_type((void **)p->output, DOUBLE_IMG,
-                              p->onaxes[1]*p->onaxes[0],
-                              p->numnul, &array, p->inputbitpix);
-
   /* Add the appropriate headers: */
-  gal_fits_file_name_in_keywords("INF", p->up.inputname, &headers);
+  gal_fits_key_write_filename("INF", p->inputname, &headers);
   for(i=0;i<9;++i)
     {
       sprintf(&keyword[i*FLEN_KEYWORD], "WMTX%zu_%zu", i/3+1, i%3+1);
-      gal_fits_add_to_key_ll_end(&headers, TDOUBLE,
+      gal_fits_key_add_to_ll_end(&headers, GAL_DATA_TYPE_FLOAT64,
                                  &keyword[i*FLEN_KEYWORD], 0,
-                                 &p->matrix[i], 0, "Warp matrix "
-                                 "element value.", 0, NULL);
+                                 &m[i], 0, "Warp matrix element value", 0,
+                                 NULL);
     }
 
   /* Due to floating point errors extremely small values of PC matrix can
      be set to zero and extremely small differences between PC1_1 and PC2_2
      can be ignored. The reason for all the `fabs' functions is because the
      signs are usually different.*/
-  if( p->wcs->pc[1]<ABSOLUTEFLTERROR ) p->wcs->pc[1]=0.0f;
-  if( p->wcs->pc[2]<ABSOLUTEFLTERROR ) p->wcs->pc[2]=0.0f;
-  pixelscale=gal_wcs_pixel_scale_deg(p->wcs);
-  diff=fabs(p->wcs->pc[0])-fabs(p->wcs->pc[3]);
+  if( wcs->pc[1]<ABSOLUTEFLTERROR ) wcs->pc[1]=0.0f;
+  if( wcs->pc[2]<ABSOLUTEFLTERROR ) wcs->pc[2]=0.0f;
+  pixelscale=gal_wcs_pixel_scale_deg(wcs);
+  diff=fabs(wcs->pc[0])-fabs(wcs->pc[3]);
   if( fabs(diff/pixelscale[0])<RELATIVEFLTERROR )
-    p->wcs->pc[3] =  ( (p->wcs->pc[3] < 0.0f ? -1.0f : 1.0f)
-                       * fabs(p->wcs->pc[0]) );
+    wcs->pc[3] =  ( (wcs->pc[3] < 0.0f ? -1.0f : 1.0f) * fabs(wcs->pc[0]) );
 
-  /* Save the output: */
-  gal_fits_array_to_file(p->cp.output, "Warped", p->inputbitpix, array,
-                         p->onaxes[1], p->onaxes[0], p->numnul, p->wcs,
-                         headers, SPACK_STRING);
+  /* Save the output into the proper type and write it. */
+  if(p->cp.type!=p->output->type)
+    p->output=gal_data_copy_to_new_type_free(p->output, p->cp.type);
+  gal_fits_img_write(p->output, p->cp.output, headers, PROGRAM_STRING);
 
   /* Clean up. */
   free(pixelscale);
-  if(array!=p->output)
-    free(array);
 }
 
 
@@ -525,18 +493,16 @@ correctwcssaveoutput(struct warpparams *p)
 /**************       Outside function        ******************/
 /***************************************************************/
 void
-warp(struct imgwarpparams *p)
+warp(struct warpparams *p)
 {
   int err;
   pthread_t t;          /* All thread ids saved in this, not used. */
   pthread_attr_t attr;
   pthread_barrier_t b;
   struct iwpparams *iwp;
+  size_t nt=p->cp.numthreads;
   size_t i, nb, *indexs, thrdcols;
-  size_t nt=p->cp.numthreads, size;
 
-  /* Set the number of output blank pixels to zero: */
-  p->numnul=0;
 
   /* Array keeping thread parameters for each thread. */
   errno=0;
@@ -551,8 +517,7 @@ warp(struct imgwarpparams *p)
 
 
   /* Distribute the output pixels into the threads: */
-  size=p->onaxes[0]*p->onaxes[1];
-  gal_threads_dist_in_threads(size, nt, &indexs, &thrdcols);
+  gal_threads_dist_in_threads(p->output->size, nt, &indexs, &thrdcols);
 
 
   /* Start the convolution. */
@@ -568,8 +533,8 @@ warp(struct imgwarpparams *p)
          (that spinns off the nt threads) is also a thread, so the
          number the barrier should be one more than the number of
          threads spinned off. */
-      if(size<nt) nb=size+1;
-      else nb=nt+1;
+      if(p->output->size<nt) nb=p->output->size+1;
+      else                   nb=nt+1;
       gal_threads_attr_barrier_init(&attr, &b, nb);
 
       /* Spin off the threads: */
@@ -590,11 +555,13 @@ warp(struct imgwarpparams *p)
       pthread_barrier_destroy(&b);
     }
 
-  /* Correct the WCS information and save the output. */
-  correctwcssaveoutput(p);
+
+  /* Save the output. */
+  correct_wcs_save_output(p);
+
 
   /* Free the allocated spaces: */
   free(iwp);
   free(indexs);
-  free(p->output);
+  gal_data_free(p->output);
 }
diff --git a/bin/warp/warp.h b/bin/warp/warp.h
index 5bf188b..9e48dd4 100644
--- a/bin/warp/warp.h
+++ b/bin/warp/warp.h
@@ -45,6 +45,6 @@ struct iwpparams
 
 /* Extenal functions. */
 void
-warp(struct imgwarpparams *p);
+warp(struct warpparams *p);
 
 #endif
diff --git a/bootstrap.conf b/bootstrap.conf
index b4b0587..364efbd 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -163,13 +163,14 @@ bootstrap_post_import_hook()
              printf "\n";                                                   \
              print "  /* Function to process the given value.";             \
              print "     Arguments to the function:";                       \
-             print "       struct argp_option *option: This structure.";    \
+             print "       struct argp_option *option: This argp_option.";  \
              print "       char      *arg: String given by the user.";      \
-             print "       void *filename: Filename option was read from."; \
+             print "       char *filename: Filename option was read from."; \
              print "       size_t  lineno: Line number of option in file."; \
+             print "       void   *struct: Pointer to main program struct.";\
              print "";                                                      \
              print "     IMPORTANT: A Gnuastro addition. */";               \
-             print "  void (*func)(struct argp_option *, char *, char *, 
size_t);";  \
+             print "  void *(*func)(struct argp_option *, char *, char *, 
size_t, void *);";  \
                                                                             \
              print;                                                         \
              inargp=0;                                                      \
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index f77f600..a25a7cc 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -538,7 +538,6 @@ Gnuastro library
 
 FITS files (@file{fits.h})
 
-* CFITSIO datatype::            Addressing different types of data
 * FITS macros and data structures::  Gnuastro FITS related macros and 
structures.
 * FITS functions::              Functions to work on FITS data.
 
@@ -10091,159 +10090,159 @@ applications, see @ref{PSF}.
 The general template for invoking Warp is:
 
 @example
-$ astwarp [OPTIONS...] [matrix.txt] InputImage
+$ astwarp [OPTIONS...] InputImage
 @end example
 
 @noindent
 One line examples:
 
 @example
-$ astwarp matrix.txt image.fits
 $ astwarp --rotate=37.92 --scale=0.8 image.fits
-$ astwarp --scale 1.82 --translate 2.1 image.fits
+$ astwarp --scale 8/3 --translate 2.1 image.fits
 $ astwarp --align rawimage.fits --output=aligned.fits
-$ astwarp --matrix=0.2,0,0.4,0,0.2,0.4,0,0,1 image.fits
-$ astwarp --matrix="0.7071,-0.7071  0.7071,0.7071" image.fits
+$ astwarp --matrix=1/5,0,4/10,0,1/5,4/10,0,0,1 image.fits
+$ astwarp --matrix="0.7071,-0.7071,  0.7071,0.7071" image.fits
 @end example
 
-Warp can accept two arguments, one (an image) is mandatory if any
-processing is to be done. An optional argument is a plain text file, which
-must contain the warp/transform matrix, see @ref{Warping basics}. When this
-text file is specified, then all options related to the matrix will be
-ignored (see below for the options). As in all Gnuastro programs, when an
-output is not explicitly set with the @option{--output} option, the output
-filename will be set automatically based on the operation, see
address@hidden output}. For the full list of general options to all
-Gnuastro programs (including Warp), please see @ref{Common options}.
-
-To be the most accurate the input image will be converted to double
-precision floating points and all the processing will be done in this
-format. By default, in the end, the output image will be converted
-back to the input image data type. Note that if the input type was not
-a floating point format, then the floating point output pixels are
-going to be rounded to the nearest integer (using the @code{round}
-function in the C programming language) which can lead to a loss of
-data. This behavior can be disabled with the @option{--doubletype}
-option. The input file and input warping matrix elements are stored in
-the output's header.
-
-When using options, warps can be specified in a modular form, with options
-to specify each transformation (for example @option{--rotate}, or
address@hidden), or directly as a matrix (with @option{--matrix}). If
-specified together, the latter (direct matrix) will take precedence and all
-the modular warpings will be ignored. Any number of modular warpings can be
-specified on the command-line and configuration files. If more than one
-modular warping is given, all will be merged to create one warping
-matrix. As described in @ref{Merging multiple warpings}, matrix
-multiplication is not commutative, so the order of specifying the modular
-warpings on the command-line, and/or configuration files makes a difference
-(see @ref{Configuration file precedence}). Below, the modular warpings are
-first listed (see @ref{Warping basics} for the definition of each type of
-warping), then the other Warp options.
+If any processing is to be done, Warp can accept one file as input. As in
+all Gnuastro programs, when an output is not explicitly set with the
address@hidden option, the output filename will be set automatically
+based on the operation, see @ref{Automatic output}. For the full list of
+general options to all Gnuastro programs (including Warp), please see
address@hidden options}.
+
+To be the most accurate, the input image will be read as a 64-bit double
+precision floating point dataset and all internal processing is done in
+this format (including the raw output type). You can use the common
address@hidden option to write the output in any type you want, see
address@hidden data types}.
+
+Warps must be specified as command-line options, either as (possibly
+multiple) modular warpings (for example @option{--rotate}, or
address@hidden), or directly as a single raw matrix (with
address@hidden). If specified together, the latter (direct matrix) will
+take precedence and all the modular warpings will be ignored. Any number of
+modular warpings can be specified on the command-line and configuration
+files. If more than one modular warping is given, all will be merged to
+create one warping matrix. As described in @ref{Merging multiple warpings},
+matrix multiplication is not commutative, so the order of specifying the
+modular warpings on the command-line, and/or configuration files makes a
+difference (see @ref{Configuration file precedence}). The full list of
+modular warpings and the other options particular to Warp are described
+below.
+
+The values to the warping options (modular warpings as well as
address@hidden), are a sequence of at least one number. Each number in
+this seqence is separated from the next by a comma (@key{,}). Each number
+can also be written as a single fraction (with a forward-slash @key{/}
+between the numerator and denomiator). Space and Tab characters are
+permitted between any two numbers, just don't forget to quote the whole
+value. Otherwise, the value will not be fully passed onto the option. See
+the examples above as a demonstration.
 
 @cindex FITS standard
 Based on the FITS standard, integer values are assigned to the center of a
-pixel and the coordinate [1.0, 1.0] is the center of the bottom left
-(first) image pixel. So the point [0.0, 0.0] is half a pixel away (in each
-axis) from the bottom left vertice of the first pixel. The resampling that
-is done in Warp (see @ref{Resampling}) is dependent on this coordinate. So
-correction is done internally. With this resampling, the image must be
-warped relative to the bottom left vertice of the bottom left pixel and
-that point should lie at [0.0, 0.0]. So for a correct sampling, the warping
-center must first be translated by [0.5, 0.5], then the warp should be done
-and finally, a [-0.5, -0.5] translation should be specified. This
-correction is done internally in the following cases and can be disabled
-with the @option{--nofitscorrect} option.
-
address@hidden
address@hidden
-A 2D matrix is given in a file (as an argument).
address@hidden
-A 2D matrix is specified with the @option{--matrix} option.
address@hidden
-When modular warpings are used.
address@hidden itemize
+pixel and the coordinate [1.0, 1.0] is the center of the first pixel
+(bottom left of the image when viewed in SAO DS9). So the coordinate center
+[0.0, 0.0] is half a pixel away (in each axis) from the bottom left vertice
+of the first pixel. The resampling that is done in Warp (see
address@hidden) is done on the coordinate axises and thus directly
+depends on the coordinate center. In some situations this if fine, for
+example when rotating/aligning a real image, all the edge pixels will be
+similiarly affected. But in other situations (for example when scaling an
+over-sampled mock image to its intended resolution, this is not desired:
+you want the center of the coordinates to be on the corner of the pixel. In
+such cases, you can use the @option{--centeroncorner} option which will
+shift the center by @mymath{0.5} before the main warp, then shift it back
+by @mymath{-0.5} after the main warp, see below.
 
 
 @table @option
 
 @item -a
 @itemx --align
-Align the image and celestial (WCS) axes, such that the vertical image
-direction (when viewed in SAO ds9) corresponds to the declination and the
-horizontal axis is the inverse of the Right Ascension (RA). The inverse of
-the RA is chosen so the image can correspond to what you would actually see
-on the sky and is common in most survey images. Align is internally treated
-just like a rotation (@option{--rotation}), but uses the input image's WCS
-to find the rotation angle.
+Align the image and celestial (WCS) axes given in the input. After it, the
+vertical image direction (when viewed in SAO ds9) corresponds to the
+declination and the horizontal axis is the inverse of the Right Ascension
+(RA). The inverse of the RA is chosen so the image can correspond to what
+you would actually see on the sky and is common in most survey
+images.
+
+Align is internally treated just like a rotation (@option{--rotation}), but
+uses the input image's WCS to find the rotation angle. Thus, if you have
+rotated the image before calling @option{--align}, you might get unexpected
+results (because the rotation is defined on the original WCS).
 
 @item -r FLT
 @itemx --rotate=FLT
-Rotate the input image by the given angle in degrees. Note that commonly,
-the WCS structure of the image is set such that the RA is the inverse of
-the image horizontal axis which increases towards the right in the FITS
-standard and as viewed by SAO ds9. So the default center for rotation is on
-the right of the image. If you want to rotate about other points, you have
-to translate the warping center first (with @option{--translate}) then
-apply your rotation and then return the center back to the original
-position (with another call to @option{--translate},z see @ref{Merging
-multiple warpings}.
+Rotate the input image by the given angle in degrees: @mymath{\theta} in
address@hidden basics}. Note that commonly, the WCS structure of the image is
+set such that the RA is the inverse of the image horizontal axis which
+increases towards the right in the FITS standard and as viewed by SAO
+ds9. So the default center for rotation is on the right of the image. If
+you want to rotate about other points, you have to translate the warping
+center first (with @option{--translate}) then apply your rotation and then
+return the center back to the original position (with another call to
address@hidden, see @ref{Merging multiple warpings}.
 
 @item -s FLT[,FLT]
 @itemx --scale=FLT[,FLT]
-Scale the input image by the given factor. If only one value is given, then
-both image axes will be scaled with the given value. When two values are
-given, the first will be used to scale the first axis and the second will
+Scale the input image by the given factor(s): @mymath{M} and @mymath{N} in
address@hidden basics}. If only one value is given, then both image axes will
+be scaled with the given value. When two values are given (separated by a
+comma), the first will be used to scale the first axis and the second will
 be used for the second axis. If you only need to scale one axis, use
address@hidden for the axis you don't need to scale.
address@hidden for the axis you don't need to scale. The value(s) can also be
+written (on the command-line or in configuration files) as a fraction.
 
 @item -f FLT[,FLT]
 @itemx --flip=FLT[,FLT]
-Flip the image around the first, second or both axes. The first value
-specifies a flip on the first axis and the second on the second axis. The
-values of the option only matter if they are non-zero. If any of the values
-are zero, that axis is not flipped. So if you want to flip by the second
-axis only, use @option{--flip=0,1} (which is equivalent to
address@hidden,20} since it only matters if it is non-zero).
+Flip the input image around the given axis(s). If only one value is given,
+then both image axes are flipped. When two values are given (separated by a
+comma), you can choose which axis to flip over. @option{--flip} only takes
+values @code{0} (for no flip), or @code{1} (for a flip). Hence, if you want
+to flip by the second axis only, use @option{--flip=0,1}.
 
 @item -e FLT[,FLT]
 @itemx --shear=FLT[,FLT]
-Apply a shear to the image along the image axes. If only one value is
-given, then both image axes will be sheared with the given value. When two
-values are given, the first will be used to shear the first axis and the
-second will be used for the second axis. If you only need to shear one
-axis, use @option{0} for the axis you don't need.
+Shear the input image by the given value(s): @mymath{A} and @mymath{B} in
address@hidden basics}. If only one value is given, then both image axes will
+be sheared with the given value. When two values are given (separated by a
+comma), the first will be used to shear the first axis and the second will
+be used for the second axis. If you only need to shear along one axis, use
address@hidden for the axis that must be untouched. The value(s) can also be
+written (on the command-line or in configuration files) as a fraction.
 
 @item -t FLT[,FLT]
 @itemx --translate=FLT[,FLT]
-Apply a translation to the image along the image axes. If only one value is
-given, then both image axes will be translated with the given value. When
-two values are given, the first will be used to translate along the first
-axis and the second will be used for the second axis. If you only need to
-translate one axis, use @option{0} for the axis you don't need.
+Translate (move the center of coordinates) the input image by the given
+value(s): @mymath{c} and @mymath{f} in @ref{Warping basics}. If only one
+value is given, then both image axes will be translated by the given
+value. When two values are given (separated by a comma), the first will be
+used to translate the first axis and the second will be used for the second
+axis. If you only need to translate along one axis, use @option{0} for the
+axis that must be untouched. The value(s) can also be written (on the
+command-line or in configuration files) as a fraction.
 
 @item -p FLT[,FLT]
 @itemx --project=FLT[,FLT]
-Apply a projection to the image along the image axes. If only one value is
-given, then the projection will be applied on both image axes with the
-given value. When two values are given, the first will be used for the
+Apply a projection to the input image by the given values(s): @mymath{g}
+and @mymath{h} in @ref{Warping basics}. If only one value is given, then
+projection will apply to both axises with the given value. When two values
+are given (separated by a comma), the first will be used to project the
 first axis and the second will be used for the second axis. If you only
-need projection along one axis, use @option{0} for the axis you don't need.
+need to project along one axis, use @option{0} for the axis that must be
+untouched. The value(s) can also be written (on the command-line or in
+configuration files) as a fraction.
 
 @item -m STR
 @itemx --matrix=STR
 The warp/transformation matrix. All the elements in this matrix must be
-separated by any number of space, tab or comma (@key{,}) characters. If you
-want to use the first two, then be sure to wrap the matrix within double
-quotation marks (@key{"}) so they are not confused with other arguments on
-the command-line, see @ref{Options}. This also applies to values in the
-configuration files, see @ref{Configuration file format}.
-
-The transformation matrix can be either 2 by 2 or 3 by 3 array. In the
-former case (if a 2 by 2 matrix is given), then it is converted to a 3 by 3
-matrix with two translation terms added to correct for the FITS definition
-of position (see @ref{Warping basics}, @ref{Merging multiple warpings}, and
-the explanations above for more).
+separated by comas(@key{,}) characters and as described above, you can also
+use fractions (a forward-slash between two numbers). The transformation
+matrix can be either a 2 by 2 (4 numbers), or a 3 by 3 (9 numbers)
+array. In the former case (if a 2 by 2 matrix is given), then it is put
+into a 3 by 3 matrix (see @ref{Warping basics}).
 
 @cindex NaN
 The determinant of the matrix has to be non-zero and it must not
@@ -10252,9 +10251,17 @@ elements of the matrix have to be written row by row. 
So for the
 general homography matrix of @ref{Warping basics}, it should be called
 with @command{--matrix=a,b,c,d,e,f,g,h,1}.
 
address@hidden --nofitscorrect
-Do not correct for the FITS definition of the pixel center as described in
-the descriptions above.
+The raw matrix takes precedence over all the modular warping options listed
+above, so if it is called with any number of modular warps, the latter are
+ignored.
+
address@hidden -c
address@hidden --centeroncorer
+Put the center of coordinates on the corner of the first (bottom-left when
+viewed in SAO DS9) pixel. This option is applied after the final warping
+matrix has been finalized: either through modular warpings or the raw
+matrix. See the explanation above for coordinates in the FITS standard to
+better understand this option and when it should be used.
 
 @item --hstartwcs=INT
 Specify the first header keyword number (line) that should be used to read
@@ -10264,51 +10271,28 @@ the WCS information, see the full explanation in 
@ref{Invoking astcrop}.
 Specify the last header keyword number (line) that should be used to read
 the WCS information, see the full explanation in @ref{Invoking astcrop}.
 
address@hidden -n
address@hidden --nowcscorrection
address@hidden -k
address@hidden --keepwcs
 @cindex WCSLIB
 @cindex World Coordinate System
 Do not correct the WCS information of the input image and save it untouched
 to the output image. By default the WCS (World Coordinate System)
-information of the input image is going to be corrected in the output
-image. WCSLIB will save the input WCS information in the @code{PC}
address@hidden E.W., Calabretta M.R. (2002) Representation of
-world coordinates in FITS. Astronomy and Astrophysics, 395, 1061-1075.}. To
-correct the WCS, Warp multiplies the @code{PC} matrix with the inverse of
-the specified transformation matrix. Also the @code{CRPIX} point is going
-to be changed to its correct place in the output image coordinates. This
-behavior can be disabled with the @option{--nowcscorrection} option.
-
address@hidden Blank pixel
address@hidden Pixel, blank
address@hidden -z
address@hidden --zerofornoinput
-Set output pixels which do not correspond to any input to zero. By
-default they are set to blank pixel values, see @ref{Blank pixels}.
-
address@hidden -b FLT
address@hidden --maxblankfrac=FLT
-(@option{=FLT}) The maximum fractional area of blank pixels over the
-output pixel. If an output pixel is covered by blank pixels (see
address@hidden pixels}) for a larger fraction than the value to this
-option, the output pixel will be set to a blank pixel its self.
-
-When the fraction is lower, the sum of non-blank pixel values over
-that pixel will be multiplied by the inverse of this fraction to
-correct for its flux and not cause discontinuities on the edges of
-blank regions. Note that even with this correction, discontinuities
-(very low non-blank values touching blank regions in the output image)
-might arise depending on the transformation and the blank pixels. So
-if there are blank pixels in the image, a good value to this option
-has to be found for that particular image and warp.
-
address@hidden -d
address@hidden --doubletype
-By default the output image is going to have the same type as the
-input image. If this option is called, the output will be in double
-precision floating point format irrespective of the input data
-type. When dealing with integer input formats, this option can be
-useful in checking the results.
+information of the input image is going to be corrected in the output image
+so the objects in the image are at the same WCS coordinates. But in some
+cases it might be useful to keep it unchanged (for example to correct
+alignments).
+
address@hidden -C FLT
address@hidden --coveredfrac=FLT
+Depending on the warp, the output pixels that cover pixels on the edge of
+the input image, or blank pixels in the input image, are not going to be
+fully covered by input data. With this option, you can specify the
+acceptable covered fraction of such pixels (any value between 0 and 1). If
+you only want output pixels that are fully covered by the input image area
+(and are not blank), then you can set
address@hidden Alternatively, a value of @code{0} will keep
+output pixels that are even infinitesmially covered by the input(so the sum
+of the pixels in the input and output images will be the same).
 
 @end table
 
@@ -16169,79 +16153,19 @@ All the functions and macros introduced in this 
section are declared in
 @file{gnuastro/fits.h}.  When you include this header, you are also
 including CFITSIO's @file{fitsio.h} header. So you don't need to explicitly
 include @file{fitsio.h} anymore and can freely use any of its macros or
-functions in your code along with those discussed here. In @ref{CFITSIO
-datatype} we first have a look at the way data types are referenced in
-CFITSIO (and thus Gnuastro). @ref{FITS macros and data structures} defines
-the macros and data structures that can be used in functions for a unified
-format. This subsection finished with @ref{FITS functions}, which introduce
-the different Gnuastro functions available.
+functions in your code along with those discussed here. @ref{FITS macros
+and data structures} defines the macros and data structures that can be
+used in functions for a unified format. This subsection finished with
address@hidden functions}, which introduce the different Gnuastro functions
+available.
 
 @menu
-* CFITSIO datatype::            Addressing different types of data
 * FITS macros and data structures::  Gnuastro FITS related macros and 
structures.
 * FITS functions::              Functions to work on FITS data.
 @end menu
 
address@hidden CFITSIO datatype, FITS macros and data structures, FITS files, 
FITS files
address@hidden CFITSIO @code{datatype}
-
address@hidden Data type
address@hidden Type of data
address@hidden FITS: data type
-Data can have multiple types: standards to convert a number of bits (which
-can only have values of 0 and 1) to different number formats (for example
-integer or floating point numbers). To store data, the FITS standard
-defines two major formats: images and tables. An image has a single type
-for all its data elements (a pixel in a 2D image). A table has a single
-type for every one of its columns. In both cases, the FITS header stores
-this information. All the FITS data types correspond to C types (for
-example @code{short}, @code{int}, @code{float}, or @code{long}).
-
address@hidden CFITSIO
address@hidden @code{BITPIX}
-In images, the @code{BITPIX} header keyword specifies the type of data in
-each pixel. Within CFITSIO, the different acceptable values of
address@hidden are stored as macros ending with @code{_IMG}. For example
address@hidden, or @code{DOUBLE_IMG}. See Section 4.1, ``CFITSIO
-Definitions'', in the CFITSIO manual for the recognized CFITSIO types and
-their macros. However, the FITS standard also accepts tables: each column
-in a FITS table has a unique @code{TFORM} header keyword which specifies
-the type of data in that column. The variety of types in a FITS table can
-be much larger than an image and thus the standard for identifying them
-differs.
-
-To address these different formats of identifying the type in a uniform
-infra-structure, CFITSIO identifies a general collection of macros
-referring to types which can be internally used in all cases (images and
-tables). Thus in CFITSIO, the variable name @code{datatype} when we are
-referring to this general collection of types. The image types are a subset
-of the table column types, so each acceptable @code{datatype} corresponds
-to one of the table types. The macros for each recognized CFITSIO
address@hidden start with @code{T}, for example @code{TBYTE},
address@hidden In CFITSIO (and thus here in Gnuastro), the @code{datatype}
-is most commonly used, so this variable only accepts one of the accepted
address@hidden macros. When the @code{BITPIX} value is desired (as input or
-output), the variable is called @code{bitpix}.
-
-In Gnuastro, the functions @code{gal_fits_bitpix_to_datatype} and
address@hidden are provided to convert @code{bitpix} and
address@hidden values to @code{datatype}.
-
address@hidden
address@hidden
address@hidden @file{stdint.h}
address@hidden integer types:} CFITSIO does not use the standard fixed
-integer size types of @file{stdint.h}! It uses the subjective @code{short},
address@hidden and @code{long} variables which can differ in size from system
-to system. For example, the FITS standard defines @code{LONG_IMG} as a
-32bit signed integer type, but CFITSIO converts it to a local @code{long}
-which is 64 bits on a modern (64 bit) machine. To use CFITSIO, we had to
-adopt the same convention in Gnuastro. This issue can cause confusions, so
-be careful!
address@hidden cartouche
-
 
address@hidden FITS macros and data structures, FITS functions, CFITSIO 
datatype, FITS files
address@hidden FITS macros and data structures, FITS functions, FITS files, 
FITS files
 @subsubsection FITS macros and data structures
 
 To facilitate handling of fixed/standard values and store, or pass multiple
@@ -16268,8 +16192,7 @@ datatypes in CFITSIO (see @ref{Blank pixels} for a 
discussion on blank
 values). The values for the different types are mostly the lowest or
 highest possible value for that type (for unsigned types and 8-bit types,
 the maximum is used). So you can safely ignore the actual value and simply
-use these values to check. See explanation under the @ref{CFITSIO datatype}
-function for more on types of data in FITS.
+use these values to check.
 
 @cindex NaN
 @cindex isnan
@@ -16362,10 +16285,10 @@ struct gal_fits_key_ll
 @subsubsection FITS functions
 
 Gnuastro provides the following functions to deal with FITS data related
-operations. FITS data can have a variety of types, see @ref{CFITSIO
-datatype} for a discussion on this, in particular the integer variables
-named @code{datatype}, @code{bitpix}, and @code{tform}. See @ref{FITS
-macros and data structures} for the structure and macro definitions.
+operations. FITS data can have a variety of types, in particular the
+integer variables named @code{datatype}, @code{bitpix}, and
address@hidden See @ref{FITS macros and data structures} for the structure
+and macro definitions.
 
 @deftypefun void gal_fits_io_error (int @code{status}, char @code{*message})
 Report the input or output error as a string and print it along with a
@@ -16411,18 +16334,15 @@ this function will return an error and abort.
 @deftypefun {void *} gal_fits_datatype_blank (int @code{datatype})
 Allocate the necessary space and put the blank value of type
 @code{datatype} in it. Finally, return the pointer to the allocated
-space. This pointer is commonly necessary when calling CFITSIO read
-functions as @code{nulval}. See @ref{CFITSIO datatype}.
+space.
 @end deftypefun
 
 @deftypefun {void *} gal_fits_datatype_alloc (size_t @code{size}, int 
@code{datatype})
-Allocate an array of @code{size} elements of type @code{datatype}. See
address@hidden datatype}.
+Allocate an array of @code{size} elements of type @code{datatype}.
 @end deftypefun
 
 @deftypefun size_t gal_fits_datatype_size (int @code{datatype})
-Return the size (in bytes) of the type specified by @code{datatype}, see
address@hidden datatype}.
+Return the size (in bytes) of the type specified by @code{datatype}.
 @end deftypefun
 
 @deftypefun void gal_fits_blank_to_value (void @code{*array}, int 
@code{datatype}, size_t @code{size}, void @code{*value})
diff --git a/lib/commonopts.h b/lib/commonopts.h
index 2535659..0c67391 100644
--- a/lib/commonopts.h
+++ b/lib/commonopts.h
@@ -63,7 +63,7 @@ struct argp_option gal_commonopts_options[] =
       "Col. selection field: `name', `unit', `comment'.",
       GAL_OPTIONS_GROUP_INPUT,
       &cp->searchin,
-      GAL_DATA_TYPE_UINT8,
+      GAL_DATA_TYPE_STRING,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET,
@@ -109,10 +109,10 @@ struct argp_option gal_commonopts_options[] =
       GAL_OPTIONS_KEY_TYPE,
       "STR",
       0,
-      "Data type of output: e.g., int16, float32, etc...",
+      "Type of output: e.g., int16, float32, etc...",
       GAL_OPTIONS_GROUP_OUTPUT,
       &cp->type,
-      GAL_DATA_TYPE_UINT8,
+      GAL_DATA_TYPE_STRING,
       GAL_OPTIONS_RANGE_GT_0,
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET,
@@ -126,7 +126,7 @@ struct argp_option gal_commonopts_options[] =
       "Output table format: `fits-ascii', `fits-binary'.",
       GAL_OPTIONS_GROUP_OUTPUT,
       &cp->tableformat,
-      GAL_DATA_TYPE_UINT8,
+      GAL_DATA_TYPE_STRING,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET,
diff --git a/lib/fits.c b/lib/fits.c
index ed99382..2c33a4e 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -219,7 +219,7 @@ gal_fits_bitpix_to_type(int bitpix)
 
 
 int
-gal_fits_type_to_bitpix(int type)
+gal_fits_type_to_bitpix(uint8_t type)
 {
   switch(type)
     {
@@ -258,7 +258,7 @@ gal_fits_type_to_bitpix(int type)
    of the column. So this function will do the conversion based on the
    CFITSIO manual.*/
 char
-gal_fits_type_to_bin_tform(int type)
+gal_fits_type_to_bin_tform(uint8_t type)
 {
   switch(type)
     {
@@ -300,7 +300,7 @@ gal_fits_type_to_bin_tform(int type)
 
 
 int
-gal_fits_type_to_datatype(int type)
+gal_fits_type_to_datatype(uint8_t type)
 {
   int w=0;
 
@@ -790,7 +790,7 @@ gal_fits_key_read(char *filename, char *hdu, gal_data_t 
*keysll,
    it is important to know before hand if they were allocated or
    not. If not, they don't need to be freed. */
 void
-gal_fits_key_add_to_ll(struct gal_fits_key_ll **list, int type,
+gal_fits_key_add_to_ll(struct gal_fits_key_ll **list, uint8_t type,
                        char *keyname, int kfree, void *value, int vfree,
                        char *comment, int cfree, char *unit)
 {
@@ -820,7 +820,7 @@ gal_fits_key_add_to_ll(struct gal_fits_key_ll **list, int 
type,
 
 
 void
-gal_fits_key_add_to_ll_end(struct gal_fits_key_ll **list, int type,
+gal_fits_key_add_to_ll_end(struct gal_fits_key_ll **list, uint8_t type,
                            char *keyname, int kfree, void *value, int vfree,
                            char *comment, int cfree, char *unit)
 {
@@ -1237,7 +1237,7 @@ gal_fits_img_read(char *filename, char *hdu, size_t 
minmapsize)
    this input to be a special type. For such cases, this function can be
    used to convert the input file to the desired type. */
 gal_data_t *
-gal_fits_img_read_to_type(char *inputname, char *hdu, int type,
+gal_fits_img_read_to_type(char *inputname, char *hdu, uint8_t type,
                           size_t minmapsize)
 {
   gal_data_t *in, *converted;
@@ -1340,6 +1340,7 @@ gal_fits_img_write_to_ptr(gal_data_t *data, char 
*filename)
     fits_create_file(&fptr, filename, &status);
 
   /* Create the FITS file. */
+
   fits_create_img(fptr, gal_fits_type_to_bitpix(data->type),
                   data->ndim, naxes, &status);
   gal_fits_io_error(status, NULL);
diff --git a/lib/gnuastro/fits.h b/lib/gnuastro/fits.h
index ba7efd8..f491876 100644
--- a/lib/gnuastro/fits.h
+++ b/lib/gnuastro/fits.h
@@ -79,7 +79,7 @@ struct gal_fits_key_ll
   int                    kfree;   /* ==1, free keyword name.   */
   int                    vfree;   /* ==1, free keyword value.  */
   int                    cfree;   /* ==1, free comment.        */
-  int                     type;   /* Keyword value type.       */
+  uint8_t                 type;   /* Keyword value type.       */
   char                *keyname;   /* Keyword Name.             */
   void                  *value;   /* Keyword value.            */
   char                *comment;   /* Keyword comment.          */
@@ -124,13 +124,13 @@ int
 gal_fits_bitpix_to_type(int bitpix);
 
 int
-gal_fits_type_to_bitpix(int type);
+gal_fits_type_to_bitpix(uint8_t type);
 
 char
-gal_fits_type_to_bin_tform(int type);
+gal_fits_type_to_bin_tform(uint8_t type);
 
 int
-gal_fits_type_to_datatype(int type);
+gal_fits_type_to_datatype(uint8_t type);
 
 int
 gal_fits_datatype_to_type(int datatype, int is_table_column);
@@ -166,12 +166,12 @@ gal_fits_key_read(char *filename, char *hdu, gal_data_t 
*keysll,
                        int readcomment, int readunit);
 
 void
-gal_fits_key_add_to_ll(struct gal_fits_key_ll **list, int datatype,
+gal_fits_key_add_to_ll(struct gal_fits_key_ll **list, uint8_t type,
                        char *keyname, int kfree, void *value, int vfree,
                        char *comment, int cfree, char *unit);
 
 void
-gal_fits_key_add_to_ll_end(struct gal_fits_key_ll **list, int datatype,
+gal_fits_key_add_to_ll_end(struct gal_fits_key_ll **list, uint8_t type,
                            char *keyname, int kfree, void *value, int vfree,
                            char *comment, int cfree, char *unit);
 
@@ -203,7 +203,7 @@ gal_data_t *
 gal_fits_img_read(char *filename, char *hdu, size_t minmapsize);
 
 gal_data_t *
-gal_fits_img_read_to_type(char *inputname, char *inhdu, int type,
+gal_fits_img_read_to_type(char *inputname, char *inhdu, uint8_t type,
                           size_t minmapsize);
 
 gal_data_t *
diff --git a/lib/gnuastro/linkedlist.h b/lib/gnuastro/linkedlist.h
index 08a404f..e5121ee 100644
--- a/lib/gnuastro/linkedlist.h
+++ b/lib/gnuastro/linkedlist.h
@@ -84,6 +84,32 @@ gal_linkedlist_free_fll_array(struct gal_linkedlist_fll 
**afll,
 
 
 
+/******************* double: */
+struct gal_linkedlist_dll
+{
+    double v;
+    struct gal_linkedlist_dll *next;
+};
+void
+gal_linkedlist_add_to_dll(struct gal_linkedlist_dll **list, double value);
+
+void
+gal_linkedlist_pop_from_dll(struct gal_linkedlist_dll **list, double *value);
+
+size_t
+gal_linkedlist_num_in_dll(struct gal_linkedlist_dll *list);
+
+void
+gal_linkedlist_dll_to_array(struct gal_linkedlist_dll *list,
+                            double **d, size_t *num);
+
+void
+gal_linkedlist_free_dll(struct gal_linkedlist_dll *list);
+
+
+
+
+
 /******************* Two doubles (for coordinates) */
 struct gal_linkedlist_tdll
 {
diff --git a/lib/gnuastro/table.h b/lib/gnuastro/table.h
index fa53d82..711d912 100644
--- a/lib/gnuastro/table.h
+++ b/lib/gnuastro/table.h
@@ -125,9 +125,15 @@ enum gal_table_diplay_formats
 uint8_t
 gal_table_string_to_format(char *string);
 
+char *
+gal_table_format_as_string(uint8_t format);
+
 uint8_t
 gal_table_string_to_searchin(char *string);
 
+char *
+gal_table_searchin_as_string(uint8_t searchin);
+
 void
 gal_table_check_fits_format(char *filename, int tableformat);
 
diff --git a/lib/linkedlist.c b/lib/linkedlist.c
index 7795ec4..0e8ca06 100644
--- a/lib/linkedlist.c
+++ b/lib/linkedlist.c
@@ -182,6 +182,116 @@ gal_linkedlist_free_fll_array(struct gal_linkedlist_fll 
**afll, size_t num)
 
 
 /****************************************************************
+ *****************          Double           ********************
+ ****************************************************************/
+void
+gal_linkedlist_add_to_dll(struct gal_linkedlist_dll **list, double value)
+{
+  struct gal_linkedlist_dll *newnode;
+
+  errno=0;
+  newnode=malloc(sizeof *newnode);
+  if(newnode==NULL)
+    error(EXIT_FAILURE, errno, "linkedlist: New element in "
+          "gal_linkedlist_dll");
+
+  newnode->v=value;
+  newnode->next=*list;
+  *list=newnode;
+}
+
+
+
+
+
+void
+gal_linkedlist_pop_from_dll(struct gal_linkedlist_dll **list, double *value)
+{
+  struct gal_linkedlist_dll *tmp;
+  tmp=*list;
+  *value=tmp->v;
+  *list=tmp->next;
+  free(tmp);
+}
+
+
+
+
+
+size_t
+gal_linkedlist_num_in_dll(struct gal_linkedlist_dll *list)
+{
+  size_t num=0;
+  struct gal_linkedlist_dll *tmp;
+  for(tmp=list;tmp!=NULL;tmp=tmp->next)
+    ++num;
+  return num;
+}
+
+
+
+
+
+void
+gal_linkedlist_dll_to_array(struct gal_linkedlist_dll *list,
+                            double **d, size_t *num)
+{
+  double *td;
+  size_t i=0;
+  struct gal_linkedlist_dll *tmp;
+
+  /* Find the number of elements: */
+  *num=gal_linkedlist_num_in_dll(list);
+
+  /* Allocate the space: */
+  errno=0;
+  td=*d=malloc(*num*sizeof(double));
+  if(*d==NULL)
+    error(EXIT_FAILURE, errno, "linkedlist: array of gal_linkedlist_dll "
+          "with %zu elements", *num);
+
+  /* Fill in the array: */
+  for(tmp=list;tmp!=NULL;tmp=tmp->next)
+    td[i++]=tmp->v;
+}
+
+
+
+
+
+void
+gal_linkedlist_free_dll(struct gal_linkedlist_dll *list)
+{
+  struct gal_linkedlist_dll *tmp, *ttmp;
+  tmp=list;
+  while(tmp!=NULL)
+    {
+      ttmp=tmp->next;
+      free(tmp);
+      tmp=ttmp;
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/****************************************************************
  *****************        Two doubles        ********************
  ****************************************************************/
 void
diff --git a/lib/options.c b/lib/options.c
index 8a0b8ea..800ec72 100644
--- a/lib/options.c
+++ b/lib/options.c
@@ -174,67 +174,112 @@ options_get_home()
 
 
 
-void
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**********************************************************************/
+/************                Convert values             ***************/
+/**********************************************************************/
+void *
 gal_options_read_type(struct argp_option *option, char *arg,
-                      char *filename, size_t lineno)
+                      char *filename, size_t lineno, void *junk)
 {
-  /* If the option is already set, just return. */
-  if(option->set) return;
-
-  /* Read the value. */
-  if ( (*(uint8_t *)(option->value) = gal_data_string_as_type(arg) )
-       == GAL_DATA_TYPE_INVALID )
-    error_at_line(EXIT_FAILURE, 0, filename, lineno, "`%s' (value to "
-                  "`%s' option) couldn't be recognized as a known type.\n\n"
-                  "For the full list of known types, please run the "
-                  "following command (press SPACE key to go down, and `q' "
-                  "to return to the command-line):\n\n"
-                  "    $ info gnuastro \"Numeric data types\"\n",
-                  arg, option->name);
+  if(lineno==-1)
+    return gal_data_type_as_string( *(uint8_t *)(option->value), 1);
+  else
+    {
+      /* If the option is already set, just return. */
+      if(option->set) return NULL;
+
+      /* Read the value. */
+      if ( (*(uint8_t *)(option->value) = gal_data_string_as_type(arg) )
+           == GAL_DATA_TYPE_INVALID )
+        error_at_line(EXIT_FAILURE, 0, filename, lineno, "`%s' (value to "
+                      "`%s' option) couldn't be recognized as a known "
+                      "type.\n\nFor the full list of known types, please "
+                      "run the following command (press SPACE key to go "
+                      "down, and `q' to return to the command-line):\n\n"
+                      "    $ info gnuastro \"Numeric data types\"\n",
+                      arg, option->name);
+
+      /* For no un-used variable warning. This function doesn't need the
+         pointer.*/
+      return junk=NULL;
+    }
 }
 
 
 
 
 
-void
+void *
 gal_options_read_searchin(struct argp_option *option, char *arg,
-                          char *filename, size_t lineno)
+                          char *filename, size_t lineno, void *junk)
 {
-  /* If the option is already set, just return. */
-  if(option->set) return;
-
-  /* Read the value. */
-  if( ( *(uint8_t *)(option->value)=gal_table_string_to_searchin(arg) )
-      == GAL_TABLE_SEARCH_INVALID )
-    error_at_line(EXIT_FAILURE, 0, filename, lineno, "`%s' (value to "
-                  "`%s' option) couldn't be recognized as a known table "
-                  "search-in field (`name', `unit', or `comment').\n\n"
-                  "For more explanation, please run the following command "
-                  "(press SPACE key to go down, and `q' to return to the "
-                  "command-line):\n\n"
-                  "    $ info gnuastro \"Selecting table columns\"\n",
-                  arg, option->name);
+  if(lineno==-1)
+    return gal_table_searchin_as_string( *(uint8_t *)(option->value));
+  else
+    {
+      /* If the option is already set, just return. */
+      if(option->set) return NULL;
+
+      /* Read the value. */
+      if( ( *(uint8_t *)(option->value)=gal_table_string_to_searchin(arg) )
+          == GAL_TABLE_SEARCH_INVALID )
+        error_at_line(EXIT_FAILURE, 0, filename, lineno, "`%s' (value to "
+                      "`%s' option) couldn't be recognized as a known table "
+                      "search-in field (`name', `unit', or `comment').\n\n"
+                      "For more explanation, please run the following "
+                      "command (press SPACE key to go down, and `q' to "
+                      "return to the command-line):\n\n"
+                      "    $ info gnuastro \"Selecting table columns\"\n",
+                      arg, option->name);
+
+      /* For no un-used variable warning. This function doesn't need the
+         pointer.*/
+      return junk=NULL;
+    }
 }
 
 
 
 
 
-void
+void *
 gal_options_read_tableformat(struct argp_option *option, char *arg,
-                             char *filename, size_t lineno)
+                             char *filename, size_t lineno, void *junk)
 {
-  /* If the option is already set, then you don't have to do anything. */
-  if(option->set) return;
-
-  /* Read the value. */
-  if( (*(uint8_t *)(option->value) = gal_table_string_to_format(arg) )
-      ==GAL_TABLE_FORMAT_INVALID )
-    error_at_line(EXIT_FAILURE, 0, filename, lineno, "`%s' (value to "
-                  "`%s' option) couldn't be recognized as a known table "
-                  "format field (`txt', `fits-ascii', or `fits-binary').\n\n",
-                  arg, option->name);
+  if(lineno==-1)
+    return gal_table_format_as_string( *(uint8_t *)(option->value));
+  else
+    {
+      /* If the option is already set, then you don't have to do anything. */
+      if(option->set) return NULL;
+
+      /* Read the value. */
+      if( (*(uint8_t *)(option->value) = gal_table_string_to_format(arg) )
+          ==GAL_TABLE_FORMAT_INVALID )
+        error_at_line(EXIT_FAILURE, 0, filename, lineno, "`%s' (value to "
+                      "`%s' option) couldn't be recognized as a known table "
+                      "format field (`txt', `fits-ascii', or "
+                      "`fits-binary').\n\n", arg, option->name);
+
+      /* For no un-used variable warning. This function doesn't need the
+         pointer.*/
+      return junk=NULL;
+    }
 }
 
 
@@ -534,17 +579,28 @@ options_sanity_check(struct argp_option *option, char 
*arg,
 
 static void
 gal_options_read_check(struct argp_option *option, char *arg, char *filename,
-                       size_t lineno)
+                       size_t lineno, void *program_struct)
 {
   /* If a function is defined to process the value, then use it. */
   if(option->func)
-    option->func(option, arg, filename, lineno);
-  else
+    {
+      option->func(option, arg, filename, lineno, program_struct);
+      option->set=GAL_OPTIONS_SET;
+      return;
+    }
+
+
+  /* Check if an argument is actually given (only options given on the
+     command-line can have a NULL arg value). */
+  if(arg)
     {
       if(option->type==GAL_DATA_TYPE_STRLL)
         gal_linkedlist_add_to_stll(option->value, arg, 1);
       else
         {
+          /* If the option is already set, ignore the given value. */
+          if(option->set==GAL_OPTIONS_SET) return;
+
           /* Read the string argument into the value. */
           if( gal_data_string_to_type(&option->value, arg, option->type) )
             /* Fortunately `error_at_line' will behave like `error' when the
@@ -563,12 +619,31 @@ gal_options_read_check(struct argp_option *option, char 
*arg, char *filename,
                           "name(+value, if there are no spaces between them) "
                           "is read as the value of the previous option.", arg,
                           option->name);
+
+          /* Do a sanity check on the value. */
+          options_sanity_check(option, arg, filename, lineno);
         }
+    }
+  else
+    {
+      /* If the option is already set, ignore the given value. */
+      if(option->set==GAL_OPTIONS_SET) return;
 
-      /* Do a sanity check. */
-      options_sanity_check(option, arg, filename, lineno);
+      /* Make sure the option has the type set for options with no
+         argument. So, give it a value of 1. */
+      if(option->type==GAL_OPTIONS_NO_ARG_TYPE)
+        *(uint8_t *)(option->value)=1;
+      else
+        error(EXIT_FAILURE, 0, "A bug! Please contact us at %s to "
+              "correct it. Options with no arguments, must have "
+              "type `%s' to be read in `gal_options_read_from_key'. "
+              "However, the option with key `%d' has type %s",
+              PACKAGE_BUGREPORT,
+              gal_data_type_as_string(GAL_OPTIONS_NO_ARG_TYPE, 1),
+              option->key, gal_data_type_as_string(option->type, 1));
     }
 
+
   /* Flip the `set' flag to `GAL_OPTIONS_SET'. */
   option->set=GAL_OPTIONS_SET;
 }
@@ -628,30 +703,9 @@ gal_options_set_from_key(int key, char *arg, struct 
argp_option *options,
           if(options[i].set && gal_data_is_linked_list(options[i].type)==0)
             options[i].set=GAL_OPTIONS_NOT_SET;
 
-          /* We have two types of options: those which need an argument and
-             those that don't. For those that don't `arg' will be
-             NULL. When it accepts an argument then read itinto the option
-             structure and do a sanity check.*/
-          if(arg)
-            gal_options_read_check(&options[i], arg, NULL, 0);
-          else
-            {
-              /* Make sure the option has the type set for options with no
-                 argument. So, give it a value of 1. */
-              if(options[i].type==GAL_OPTIONS_NO_ARG_TYPE)
-                {
-                  *(unsigned char *)(options[i].value)=1;
-                  options[i].set=GAL_OPTIONS_SET;
-                }
-              else
-                error(EXIT_FAILURE, 0, "A bug! Please contact us at %s to "
-                      "correct it. Options with no arguments, must have "
-                      "type `%s' to be read in `gal_options_read_from_key'. "
-                      "However, the option with key `%d' has type %s",
-                      PACKAGE_BUGREPORT,
-                      gal_data_type_as_string(GAL_OPTIONS_NO_ARG_TYPE, 1),
-                      key, gal_data_type_as_string(options[i].type, 1));
-            }
+          /* Parse the value. */
+          gal_options_read_check(&options[i], arg, NULL, 0,
+                                 cp->program_struct);
 
 
           /* We have found and set the value given to this option, so just
@@ -823,7 +877,8 @@ options_set_from_name(char *name, char *arg,  struct 
argp_option *options,
           options_immediate(options[i].key, arg, cp);
 
           /* Read the value into the option and do a sanity check. */
-          gal_options_read_check(&options[i], arg, filename, lineno);
+          gal_options_read_check(&options[i], arg, filename, lineno,
+                                 cp->program_struct);
 
           /* We have found and set the value given to this option, so just
              return success (an error_t of 0 means success). */
@@ -1014,16 +1069,13 @@ options_reverse_lists_check_mandatory(struct 
gal_options_common_params *cp,
   for(i=0; !gal_options_is_last(&options[i]); ++i)
     {
       if(options[i].set)
-        {
-          if( gal_data_is_linked_list(options[i].type) )
-            switch(options[i].type)
-              {
-              case GAL_DATA_TYPE_STRLL:
-                gal_linkedlist_reverse_stll(
-                    (struct gal_linkedlist_stll **)(options[i].value) );
-                break;
-              }
-        }
+        switch(options[i].type)
+          {
+          case GAL_DATA_TYPE_STRLL:
+            gal_linkedlist_reverse_stll(
+                  (struct gal_linkedlist_stll **)(options[i].value) );
+            break;
+          }
       else if(options[i].mandatory==GAL_OPTIONS_MANDATORY)
         gal_options_add_to_not_given(cp, &options[i]);
     }
@@ -1079,8 +1131,14 @@ gal_options_read_config_set(struct 
gal_options_common_params *cp)
 static int
 option_is_printable(struct argp_option *option)
 {
-  /* First check if option is hidden (not relevant to this program). */
-  if(option->flags & OPTION_HIDDEN)
+  /* Use non-key fields:
+
+       - If option is hidden (not relevant to this program).
+
+       - Options with an INVALID type are not to be printed (they are
+         probably processed to a higher level value with functions). */
+  if( (option->flags & OPTION_HIDDEN)
+      || option->type==GAL_DATA_TYPE_INVALID )
     return 0;
 
   /* Then check if it is a pre-program option. */
@@ -1106,12 +1164,15 @@ option_is_printable(struct argp_option *option)
    elements. If `width==0', then return the width necessary to print the
    value. */
 static int
-options_print_any_type(void *ptr, int type, int width, FILE *fp)
+options_print_any_type(struct argp_option *option, void *ptr, int type,
+                       int width, FILE *fp)
 {
   char *str;
 
   /* Write the value into a string. */
-  str=gal_data_write_to_string(ptr, type, 1);
+  str = ( option->func
+          ? option->func(option, NULL, NULL, (size_t)(-1), NULL)
+          : gal_data_write_to_string(ptr, type, 1) );
 
   /* If only the width was desired, don't actually print the string, just
      return its length. Otherwise, print it. */
@@ -1120,8 +1181,9 @@ options_print_any_type(void *ptr, int type, int width, 
FILE *fp)
   else
     width=strlen(str);
 
-  /* Free the allocated space and return. */
-  free(str);
+  /* Free the allocated space and return. When the value was taken from a
+     function, it is static, so it must not be freed. */
+  if(!option->func) free(str);
   return width;
 }
 
@@ -1138,6 +1200,10 @@ options_correct_max_lengths(struct argp_option *option, 
int *max_nlen,
   int vlen;
   struct gal_linkedlist_stll *tmp;
 
+  /* Invalid types are set for functions that don't save the raw user
+     input, but do higher-level analysis on them for storing. */
+  if(option->type==GAL_DATA_TYPE_INVALID) return;
+
   /* Get the length of the value and save its length length if its
      larger than the widest value. */
   if(gal_data_is_linked_list(option->type))
@@ -1152,7 +1218,8 @@ options_correct_max_lengths(struct argp_option *option, 
int *max_nlen,
           tmp!=NULL; tmp=tmp->next)
         {
           /* Get the length of this node: */
-          vlen=options_print_any_type(&tmp->v, GAL_DATA_TYPE_STRING, 0, NULL);
+          vlen=options_print_any_type(option, &tmp->v, GAL_DATA_TYPE_STRING,
+                                      0, NULL);
 
           /* If its larger than the maximum length, then put it in. */
           if( vlen > *max_vlen )
@@ -1161,7 +1228,8 @@ options_correct_max_lengths(struct argp_option *option, 
int *max_nlen,
     }
   else
     {
-      vlen=options_print_any_type(option->value, option->type, 0, NULL);
+      vlen=options_print_any_type(option, option->value, option->type,
+                                  0, NULL);
       if( vlen > *max_vlen )
         *max_vlen=vlen;
     }
@@ -1260,9 +1328,9 @@ options_print_all_in_group(struct argp_option *options, 
int groupint,
 
   /* Go over all the options. */
   for(i=0; !gal_options_is_last(&options[i]); ++i)
-    if( options[i].group == groupint          /* Is in this group.        */
-        && options[i].set                     /* Has been given a value.  */
-        && option_is_printable(&options[i]) ) /* Is relevant for printing.*/
+    if( options[i].group == groupint           /* Is in this group.        */
+        && options[i].set                      /* Has been given a value.  */
+        && option_is_printable(&options[i]) )  /* Is relevant for printing.*/
       {
         /* Linked lists */
         if(gal_data_is_linked_list(options[i].type))
@@ -1270,8 +1338,8 @@ options_print_all_in_group(struct argp_option *options, 
int groupint,
               tmp!=NULL; tmp=tmp->next)
             {
               fprintf(fp, " %-*s ", namewidth, options[i].name);
-              options_print_any_type(&tmp->v, GAL_DATA_TYPE_STRING,
-                                     valuewidth, fp);
+              options_print_any_type(&options[i], &tmp->v,
+                                     GAL_DATA_TYPE_STRING, valuewidth, fp);
               options_print_doc(fp, options[i].doc, namewidth+valuewidth);
             }
 
@@ -1279,8 +1347,8 @@ options_print_all_in_group(struct argp_option *options, 
int groupint,
         else
           {
             fprintf(fp, " %-*s ", namewidth, options[i].name);
-            options_print_any_type(options[i].value, options[i].type,
-                                   valuewidth, fp);
+            options_print_any_type(&options[i], options[i].value,
+                                   options[i].type, valuewidth, fp);
             options_print_doc(fp, options[i].doc, namewidth+valuewidth);
           }
       }
@@ -1408,7 +1476,7 @@ options_print_all(struct gal_options_common_params *cp, 
char *dirname,
 
 
 
-#define OPTIONS_UCHARVAL *(unsigned char *)(cp->coptions[i].value)
+#define OPTIONS_UINT8VAL *(uint8_t *)(cp->coptions[i].value)
 void
 gal_options_print_state(struct gal_options_common_params *cp)
 {
@@ -1426,7 +1494,7 @@ gal_options_print_state(struct gal_options_common_params 
*cp)
         case GAL_OPTIONS_KEY_PRINTPARAMS:
         case GAL_OPTIONS_KEY_SETDIRCONF:
         case GAL_OPTIONS_KEY_SETUSRCONF:
-          sum += OPTIONS_UCHARVAL;
+          sum += OPTIONS_UINT8VAL;
         }
   if(sum>1)
     error(EXIT_FAILURE, 0, "only one of the `printparams', `setdirconf' "
@@ -1437,7 +1505,7 @@ gal_options_print_state(struct gal_options_common_params 
*cp)
      non-NULL value is not enough. They can have a value of 1 or 0, and the
      respective file should only be created if we have a value of 1. */
   for(i=0; !gal_options_is_last(&cp->coptions[i]); ++i)
-    if(cp->coptions[i].set && OPTIONS_UCHARVAL)
+    if(cp->coptions[i].set && OPTIONS_UINT8VAL)
       switch(cp->coptions[i].key)
         {
         case GAL_OPTIONS_KEY_PRINTPARAMS:
diff --git a/lib/options.h b/lib/options.h
index b1ddc9c..ff8c131 100644
--- a/lib/options.h
+++ b/lib/options.h
@@ -176,6 +176,7 @@ struct gal_options_common_params
   uint8_t           lastconfig; /* This is the last configuration file.  */
 
   /* For internal (to option processing) purposes. */
+  void         *program_struct; /* Host program's main variable struct.  */
   char           *program_name; /* Official name to be used in text.     */
   char           *program_exec; /* Program's executable name.            */
   char         *program_bibtex; /* BibTeX record for this program.       */
@@ -207,20 +208,23 @@ gal_options_add_to_not_given(struct 
gal_options_common_params *cp,
 void
 gal_options_abort_if_mandatory_missing(struct gal_options_common_params *cp);
 
-void
+
+
+
+/**********************************************************************/
+/************                Convert values             ***************/
+/**********************************************************************/
+void *
 gal_options_read_type(struct argp_option *option, char *arg,
-                      char *filename, size_t lineno);
+                      char *filename, size_t lineno, void *junk);
 
-void
+void *
 gal_options_read_searchin(struct argp_option *option, char *arg,
-                          char *filename, size_t lineno);
+                          char *filename, size_t lineno, void *junk);
 
-void
+void *
 gal_options_read_tableformat(struct argp_option *option, char *arg,
-                             char *filename, size_t lineno);
-
-void
-gal_options_free(struct argp_option *options);
+                             char *filename, size_t lineno, void *junk);
 
 
 
diff --git a/lib/table.c b/lib/table.c
index ae1c8d1..6da9e3c 100644
--- a/lib/table.c
+++ b/lib/table.c
@@ -49,26 +49,38 @@ gal_table_string_to_format(char *string)
 {
   if(string)                    /* Its not NULL. */
     {
-      if( !strcmp(string, "txt") )
-        return GAL_TABLE_FORMAT_TXT;
+      if(!strcmp(string, "txt"))              return GAL_TABLE_FORMAT_TXT;
+      else if(!strcmp(string,"fits-ascii"))   return GAL_TABLE_FORMAT_AFITS;
+      else if(!strcmp(string, "fits-binary")) return GAL_TABLE_FORMAT_BFITS;
+      else                                    return GAL_TABLE_FORMAT_INVALID;
+    }
+  else                                        return GAL_TABLE_FORMAT_INVALID;
+}
 
-      else if( !strcmp(string, "fits-ascii") )
-        return GAL_TABLE_FORMAT_AFITS;
 
-      else if( !strcmp(string, "fits-binary") )
-        return GAL_TABLE_FORMAT_BFITS;
 
-      else
-        return GAL_TABLE_FORMAT_INVALID;
+
+
+char *
+gal_table_format_as_string(uint8_t format)
+{
+  switch(format)
+    {
+    case GAL_TABLE_FORMAT_TXT:    return "txt";
+    case GAL_TABLE_FORMAT_AFITS:  return "fits-ascii";
+    case GAL_TABLE_FORMAT_BFITS:  return "fits-binary";
+    default:
+      error(EXIT_FAILURE, 0, "code %d not recognized as a valid format "
+            "in `gal_table_format_as_string'", format);
+      return NULL;
     }
-  else
-    return GAL_TABLE_FORMAT_INVALID;
 }
 
 
 
 
 
+
 /* In programs, the `searchin' variable is much more easier to format in as
    a description than an integer (which is what `gal_table_read_cols'
    needs). This function will check the string value and give the
@@ -78,20 +90,31 @@ gal_table_string_to_searchin(char *string)
 {
   if(string)                    /* Its not NULL. */
     {
-      if(strcmp(string, "name")==0)
-        return GAL_TABLE_SEARCH_NAME;
+      if(!strcmp(string, "name"))          return GAL_TABLE_SEARCH_NAME;
+      else if(!strcmp(string, "unit"))     return GAL_TABLE_SEARCH_UNIT;
+      else if(!strcmp(string, "comment"))  return GAL_TABLE_SEARCH_COMMENT;
+      else                                 return GAL_TABLE_SEARCH_INVALID;
+    }
+  else                                     return GAL_TABLE_SEARCH_INVALID;
+}
 
-      else if(strcmp(string, "unit")==0)
-        return GAL_TABLE_SEARCH_UNIT;
 
-      else if(strcmp(string, "comment")==0)
-        return GAL_TABLE_SEARCH_COMMENT;
 
-      else
-        return GAL_TABLE_SEARCH_INVALID;
+
+
+char *
+gal_table_searchin_as_string(uint8_t searchin)
+{
+  switch(searchin)
+    {
+    case GAL_TABLE_SEARCH_NAME:    return "name";
+    case GAL_TABLE_SEARCH_UNIT:    return "unit";
+    case GAL_TABLE_SEARCH_COMMENT: return "comment";
+    default:
+      error(EXIT_FAILURE, 0, "code %d not recognized as a valid search "
+            "field in `gal_table_searchin_as_string'", searchin);
+      return NULL;
     }
-  else
-    return GAL_TABLE_SEARCH_INVALID;
 }
 
 
diff --git a/lib/wcs.c b/lib/wcs.c
index 8c6b816..00252ff 100644
--- a/lib/wcs.c
+++ b/lib/wcs.c
@@ -210,7 +210,7 @@ gal_wcs_array_from_wcsprm(struct wcsprm *wcs)
         out[i]=wcs->cd[i];
     }
   else
-    error(EXIT_FAILURE, 0, "currently, `gal_wcs_pixel_scale_deg' only "
+    error(EXIT_FAILURE, 0, "currently, `gal_wcs_array_from_wcsprm' only "
           "recognizes PCi_ja and CDi_ja keywords");
 
   /* Return the result */
diff --git a/tests/warp/homographic.sh b/tests/warp/homographic.sh
index 213ce17..4b65c10 100755
--- a/tests/warp/homographic.sh
+++ b/tests/warp/homographic.sh
@@ -49,4 +49,4 @@ if [ ! -f $execname ] || [ ! -f $img ]; then exit 77; fi
 # Actual test script
 # ==================
 $execname $img --output=homographic.fits \
-          --matrix="0.707106781,-0.707106781,0,  0.707106781, 0.707106781,0,  
0.001,0.002,1"
+          --matrix="0.707106781,-0.707106781,0,  0.707106781, 0.707106781,0,  
0.001,0.002,1" --coveredfrac=0.5
diff --git a/tests/warp/warp_scale.sh b/tests/warp/warp_scale.sh
index 9f4022c..c20e625 100755
--- a/tests/warp/warp_scale.sh
+++ b/tests/warp/warp_scale.sh
@@ -48,4 +48,4 @@ if [ ! -f $execname ] || [ ! -f $img ]; then exit 77; fi
 
 # Actual test script
 # ==================
-$execname $img --matrix="0.2,0,0.4   0,0.2,0.4   0,0,1"
+$execname $img --scale=1/5 --centeroncorner
diff --git a/tmpfs-config-make b/tmpfs-config-make
index a3d9c0c..1224cb3 100755
--- a/tmpfs-config-make
+++ b/tmpfs-config-make
@@ -133,7 +133,7 @@ if [ ! -f Makefile ]; then
     $srcdir/configure --srcdir=$srcdir --disable-shared CFLAGS="-g -O0"      \
                       --enable-arithmetic --enable-convertt --enable-convolve\
                       --enable-cosmiccal --enable-crop --enable-header       \
-                      --enable-mkprof --enable-table
+                      --enable-mkprof --enable-table --enable-warp
 fi
 
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]