gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 4a9f811: Dimension-agnostic option names in Ma


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 4a9f811: Dimension-agnostic option names in MakeProfiles
Date: Sun, 2 Jul 2017 18:38:40 -0400 (EDT)

branch: master
commit 4a9f811848e37757579b1b405bd017f2250332f1
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Dimension-agnostic option names in MakeProfiles
    
    The options of MakeProfiles were too particular to dimensionality and WCS
    nature of a dataset, for example `--naxis1', `--xshift' and
    `--racol'. These just made too many options and adding different types of
    data would be complicated (for example in a spectrum which is a 2D image,
    we have length and wavelength as WCS). So `--ra' and `--dec' were
    meaningless, but using them was the only way.
    
    With this commit, all MakeProfiles options that had similar problems have
    been changed as discussed below. Also all the main WCS parameters can be
    defined with options now.
    
      The PC matrix, CUNIT and CTYPE world coordinate system keywords of the
      output can be set with `--pc', `--cunit' and `--ctype' options. Also the
      old `--crpixN', `--crvalN' and `--resolution' options were replaced with
      `--crpix', `--crval' and `--cdelt' options which can take multiple
      values.
    
      The new `--naxis' and `--shift' options can take multiple values for each
      dimension (separated by a comma). This replaces the old `--naxis1',
      `--naxis2' and `--xshift' and `--yshift' options.
    
      The new `--ccol' option can take the center coordinate columns of the
      catalog (in multiple calls) and the new `--mode' option is used to
      identify what standard to interpret them in (image or WCS). Together,
      these replace the old `--xcol', `--ycol', `--racol' and `--deccol'.
---
 NEWS                            |  22 ++
 bin/crop/args.h                 |   2 +-
 bin/crop/main.h                 |   2 +-
 bin/mkprof/args.h               | 195 ++++++++---------
 bin/mkprof/astmkprof.conf       |  52 +++--
 bin/mkprof/main.h               |  29 ++-
 bin/mkprof/mkprof.c             |  50 +++--
 bin/mkprof/oneprofile.c         |   6 +-
 bin/mkprof/ui.c                 | 454 ++++++++++++++++++++++++++++++----------
 bin/mkprof/ui.h                 |  27 ++-
 doc/gnuastro.texi               | 148 +++++++------
 lib/box.c                       |   3 +-
 lib/fits.c                      |   8 +-
 lib/gnuastro-internal/options.h |  17 +-
 lib/options.c                   | 415 ++++++++++++++++++++++++------------
 tests/mkprof/mosaic1.sh         |   2 +-
 tests/mkprof/mosaic2.sh         |   2 +-
 tests/mkprof/mosaic3.sh         |   2 +-
 tests/mkprof/mosaic4.sh         |   2 +-
 tests/mkprof/radeccat.sh        |   2 +-
 20 files changed, 934 insertions(+), 506 deletions(-)

diff --git a/NEWS b/NEWS
index eec8394..607dfd8 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,10 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
   the need to define a catalog. With this option, a catalog (or
   accompanying background image) must not be given.
 
+  MakeProfiles: the new `--pc', `--cunit' and `--ctype' options can be used
+  to specify the PC matrix, CUNIT and CTYPE world coordinate system
+  keywords of the output FITS file.
+
 ** Removed features
 
 ** Changed features
@@ -39,6 +43,21 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
   multiple times and the order of its calling will be used for the column
   containing the center in the respective dimension (in FITS format).
 
+  MakeProfiles: The new `--naxis' and `--shift' options can take multiple
+  values for each dimension (separated by a comma). This replaces the old
+  `--naxis1', `--naxis2' and `--xshift' and `--yshift' options.
+
+  MakeProfiles: The new `--ccol' option can take the center coordinate
+  columns of the catalog (in multiple calls) and the new `--mode' option is
+  used to identify what standard to interpret them in (image or
+  WCS). Together, these replace the old `--xcol', `--ycol', `--racol' and
+  `--deccol'.
+
+  MakeProfiles: The new `--crpix', `--crval' and `--cdelt' options now
+  accept multiple values separated by a comma. So they replace the old
+  `--crpix1', `--crpix2', `--crval1', `--crval2' and `--resolution'
+  options.
+
   `gal_fits_img_info' now also returns the name and units of the dataset
   (if they aren't NULL). So it takes two extra arguments.
 
@@ -57,6 +76,9 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
 
   MakeProfiles long options on 32bit big endian systems (bug #51341).
 
+  Pure rotation around pixel coordinate (0,0) (bug #51353).
+
+
 
 
 
diff --git a/bin/crop/args.h b/bin/crop/args.h
index 0cc9fbf..83f42fa 100644
--- a/bin/crop/args.h
+++ b/bin/crop/args.h
@@ -36,7 +36,7 @@ struct argp_option program_options[] =
       UI_KEY_MODE,
       "STR",
       0,
-      "Coordinate mode `img' or `wcs'",
+      "Coordinate mode `img' or `wcs'.",
       GAL_OPTIONS_GROUP_INPUT,
       &p->mode,
       GAL_TYPE_STRING,
diff --git a/bin/crop/main.h b/bin/crop/main.h
index d9e3f88..b1fbb02 100644
--- a/bin/crop/main.h
+++ b/bin/crop/main.h
@@ -43,7 +43,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #define MAXDIM                  2
 
 
-/* Modes of operation. */
+/* Modes to interpret coordinates. */
 enum crop_modes
 {
   IMGCROP_MODE_INVALID,         /* For sanity checks.     */
diff --git a/bin/mkprof/args.h b/bin/mkprof/args.h
index bfa8f5d..aaea679 100644
--- a/bin/mkprof/args.h
+++ b/bin/mkprof/args.h
@@ -89,30 +89,18 @@ struct argp_option program_options[] =
 
 
     {
-      "naxis1",
-      UI_KEY_NAXIS1,
-      "INT",
-      0,
-      "Number of pixels along first FITS axis.",
-      GAL_OPTIONS_GROUP_OUTPUT,
-      &p->naxes[0],
-      GAL_TYPE_LONG,
-      GAL_OPTIONS_RANGE_GT_0,
-      GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
-    },
-    {
-      "naxis2",
-      UI_KEY_NAXIS2,
-      "INT",
+      "naxis",
+      UI_KEY_NAXIS,
+      "INT[,INT,...]",
       0,
-      "Number of pixels along second FITS axis.",
+      "Merged image size along each dimension.",
       GAL_OPTIONS_GROUP_OUTPUT,
-      &p->naxes[1],
-      GAL_TYPE_LONG,
-      GAL_OPTIONS_RANGE_GT_0,
+      &p->dsize,
+      GAL_TYPE_STRING,
+      GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
+      GAL_OPTIONS_NOT_SET,
+      gal_options_parse_sizes_reverse
     },
     {
       "oversample",
@@ -216,30 +204,18 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_SET
     },
     {
-      "xshift",
-      UI_KEY_XSHIFT,
-      "FLT",
-      0,
-      "Shift profile centers and enlarge image, X axis.",
-      ARGS_GROUP_PROFILES,
-      &p->shift[0],
-      GAL_TYPE_LONG,
-      GAL_OPTIONS_RANGE_GE_0,
-      GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
-    },
-    {
-      "yshift",
-      UI_KEY_YSHIFT,
-      "FLT",
+      "shift",
+      UI_KEY_SHIFT,
+      "INT[, ...]",
       0,
-      "Shift profile centers and enlarge image, Y axis.",
+      "Shift profile centers in output image.",
       ARGS_GROUP_PROFILES,
-      &p->shift[1],
-      GAL_TYPE_LONG,
-      GAL_OPTIONS_RANGE_GE_0,
+      &p->shift,
+      GAL_TYPE_STRING,
+      GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
+      GAL_OPTIONS_NOT_SET,
+      gal_options_parse_sizes_reverse
     },
     {
       "prepforconv",
@@ -330,56 +306,31 @@ struct argp_option program_options[] =
       ARGS_GROUP_CATALOG
     },
     {
-      "xcol",
-      UI_KEY_XCOL,
-      "STR/INT",
-      0,
-      "Center along first FITS axis (horizontal).",
-      ARGS_GROUP_CATALOG,
-      &p->xcol,
-      GAL_TYPE_STRING,
-      GAL_OPTIONS_RANGE_ANY,
-      GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
-    },
-    {
-      "ycol",
-      UI_KEY_YCOL,
+      "ccol",
+      UI_KEY_CCOL,
       "STR/INT",
       0,
-      "Center along second FITS axis (vertical).",
+      "Coordinate columns (one call for each dimension).",
       ARGS_GROUP_CATALOG,
-      &p->ycol,
-      GAL_TYPE_STRING,
+      &p->ccol,
+      GAL_TYPE_STRLL,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
     {
-      "racol",
-      UI_KEY_RACOL,
-      "STR/INT",
-      0,
-      "Center right ascension.",
-      ARGS_GROUP_CATALOG,
-      &p->racol,
-      GAL_TYPE_STRING,
-      GAL_OPTIONS_RANGE_ANY,
-      GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
-    },
-    {
-      "deccol",
-      UI_KEY_DECCOL,
-      "STR/INT",
+      "mode",
+      UI_KEY_MODE,
+      "STR",
       0,
-      "Center declination.",
-      ARGS_GROUP_CATALOG,
-      &p->deccol,
+      "Coordinate mode `img' or `wcs'.",
+      GAL_OPTIONS_GROUP_INPUT,
+      &p->mode,
       GAL_TYPE_STRING,
       GAL_OPTIONS_RANGE_ANY,
-      GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
+      GAL_OPTIONS_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      ui_parse_coordinate_mode
     },
     {
       "fcol",
@@ -497,71 +448,89 @@ struct argp_option program_options[] =
       ARGS_GROUP_WCS
     },
     {
-      "crpix1",
-      UI_KEY_CRPIX1,
-      "FLT",
+      "crpix",
+      UI_KEY_CRPIX,
+      "FLT[, ...]",
       0,
-      "Pixel coordinate of reference point (axis 1).",
+      "Pixel coordinates of reference point.",
       ARGS_GROUP_WCS,
-      &p->crpix[0],
+      &p->crpix,
       GAL_TYPE_FLOAT64,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
+      GAL_OPTIONS_NOT_SET,
+      ui_parse_numbers
     },
     {
-      "crpix2",
-      UI_KEY_CRPIX2,
-      "FLT",
+      "crval",
+      UI_KEY_CRVAL,
+      "FLT[, ...]",
       0,
-      "Pixel coordinate of reference point (axis 2).",
+      "WCS coordinates of reference point.",
       ARGS_GROUP_WCS,
-      &p->crpix[1],
+      &p->crval,
       GAL_TYPE_FLOAT64,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
+      GAL_OPTIONS_NOT_SET,
+      ui_parse_numbers
     },
     {
-      "crval1",
-      UI_KEY_CRVAL1,
-      "FLT",
+      "cdelt",
+      UI_KEY_CDELT,
+      "FLT[, ...]",
       0,
-      "Right ascension at reference point (degrees).",
+      "Resolution in each dimension.",
       ARGS_GROUP_WCS,
-      &p->crval[0],
+      &p->cdelt,
       GAL_TYPE_FLOAT64,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
+      GAL_OPTIONS_NOT_SET,
+      ui_parse_numbers
     },
     {
-      "crval2",
-      UI_KEY_CRVAL2,
-      "FLT",
+      "pc",
+      UI_KEY_PC,
+      "FLT[, ...]",
       0,
-      "Declination at reference point (degrees).",
+      "WCS rotation matrix (all elements).",
       ARGS_GROUP_WCS,
-      &p->crval[1],
+      &p->pc,
       GAL_TYPE_FLOAT64,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
+      GAL_OPTIONS_NOT_SET,
+      ui_parse_numbers
     },
     {
-      "resolution",
-      UI_KEY_RESOLUTION,
-      "FLT",
+      "cunit",
+      UI_KEY_CUNIT,
+      "STR[, ... ]",
       0,
-      "Resolution of image (arcseconds/pixel).",
+      "Units of the WCS coordinates (e.g., `deg').",
       ARGS_GROUP_WCS,
-      &p->resolution,
+      &p->cunit,
       GAL_TYPE_FLOAT64,
-      GAL_OPTIONS_RANGE_GT_0,
+      GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
-      GAL_OPTIONS_NOT_SET
+      GAL_OPTIONS_NOT_SET,
+      gal_options_parse_csv_strings
+    },
+    {
+      "ctype",
+      UI_KEY_CTYPE,
+      "STR[, ... ]",
+      0,
+      "One of FITS standard WCS types.",
+      ARGS_GROUP_WCS,
+      &p->ctype,
+      GAL_TYPE_FLOAT64,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      gal_options_parse_csv_strings
     },
-
 
 
 
diff --git a/bin/mkprof/astmkprof.conf b/bin/mkprof/astmkprof.conf
index 5323e1b..bd727ce 100644
--- a/bin/mkprof/astmkprof.conf
+++ b/bin/mkprof/astmkprof.conf
@@ -18,38 +18,36 @@
 # warranty.
 
 #input
- backhdu               1
+ backhdu                   1
 
 # Output:
- naxis1             1000
- naxis2             1000
- oversample            5
- circumwidth           2
- type            float32
+ naxis             1000,1000
+ oversample                5
+ circumwidth               2
+ type                float32
 
 # Profiles:
- tunitinp              0
- numrandom         10000
- tolerance          0.01
- zeropoint          0.00
- prepforconv           0
- xshift                0
- yshift                0
+ tunitinp                  0
+ numrandom             10000
+ tolerance              0.01
+ zeropoint              0.00
 
 # Catalog:
- xcol                  2
- ycol                  3
- fcol                  4
- rcol                  5
- ncol                  6
- pcol                  7
- qcol                  8
- mcol                  9
- tcol                 10
+ mode                    img
+ ccol                      2
+ ccol                      3
+ fcol                      4
+ rcol                      5
+ ncol                      6
+ pcol                      7
+ qcol                      8
+ mcol                      9
+ tcol                     10
 
 # WCS:
- crpix1                1
- crpix2                1
- crval1                1
- crval2                1
- resolution         0.03
+ crpix                   1,1
+ crval                   1,1
+ cdelt   0.03/3600,0.03/3600
+ pc                 -1,0,0,1
+ cunit               deg,deg
+ ctype     RA---TAN,DEC--TAN
diff --git a/bin/mkprof/main.h b/bin/mkprof/main.h
index 5d62b98..041ddeb 100644
--- a/bin/mkprof/main.h
+++ b/bin/mkprof/main.h
@@ -43,6 +43,16 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #define DEGREESTORADIANS   M_PI/180.0f
 
 
+/* Modes to interpret coordinates. */
+enum coord_modes
+{
+  MKPROF_MODE_INVALID,          /* For sanity checks.     */
+
+  MKPROF_MODE_IMG,              /* Use image coordinates. */
+  MKPROF_MODE_WCS,              /* Use WCS coordinates.   */
+};
+
+
 
 /* Types of profiles. */
 enum profile_types
@@ -106,7 +116,7 @@ struct mkprofparams
   char            *backname;  /* Name of background image file name.      */
   char             *catname;  /* Name of catalog of parameters.           */
   char             *backhdu;  /* HDU of background image.                 */
-  long             naxes[2];  /* Size of the output image.                */
+  size_t             *dsize;  /* Size of the output image.                */
   uint8_t       clearcanvas;  /* Pixels in background image set to zero.  */
   gal_data_t        *kernel;  /* Parameters to define a kernel.           */
   uint8_t        oversample;  /* Oversampling scale.                      */
@@ -117,17 +127,15 @@ struct mkprofparams
   size_t          numrandom;  /* Number of radom points for integration.  */
   float           tolerance;  /* Accuracy to stop integration.            */
   uint8_t          tunitinp;  /* ==1: Truncation is in pixels, not radial.*/
-  long             shift[2];  /* Shift along axeses position of profiles. */
+  size_t             *shift;  /* Shift along axeses position of profiles. */
   uint8_t       prepforconv;  /* Shift and expand by size of first psf.   */
   float           zeropoint;  /* Magnitude of zero point flux.            */
   double        circumwidth;  /* Width of circumference (inward).         */
   uint8_t           replace;  /* Replace overlaping profile pixel values. */
   uint8_t         magatpeak;  /* Mag only for peak pixel, not all profile.*/
   uint8_t           envseed;  /* Use GSL_RNG_SEED for random seed.        */
-  char                *xcol;  /* X column of profile center.              */
-  char                *ycol;  /* Y column of profile center.              */
-  char               *racol;  /* RA column of profile center.             */
-  char              *deccol;  /* Dec column of profile center.            */
+  uint8_t              mode;  /* Coordinates in WCS or image standard.    */
+  gal_list_str_t      *ccol;  /* Columns that keep coordinates.           */
   char                *fcol;  /* Column specifying profile function.      */
   char                *rcol;  /* Effective radius of profile.             */
   char                *ncol;  /* Sersic index column of profile.          */
@@ -136,9 +144,12 @@ struct mkprofparams
   char                *mcol;  /* Magnitude column.                        */
   char                *tcol;  /* Truncation of the profiles.              */
   uint8_t       mforflatpix;  /* mcol is flat pixel value (f is 4 or 5).  */
-  double           crpix[2];  /* CRPIX FITS header keywords.              */
-  double           crval[2];  /* CRVAL FITS header keywords.              */
-  double         resolution;  /* For CDELTi FITS header keywords.         */
+  gal_data_t         *crpix;  /* CRPIX FITS header keywords.              */
+  gal_data_t         *crval;  /* CRVAL FITS header keywords.              */
+  gal_data_t         *cdelt;  /* For CDELTi FITS header keywords.         */
+  gal_data_t            *pc;  /* WCS PC matrix.                           */
+  gal_data_t         *cunit;  /* Units of each coordinate.                */
+  gal_data_t         *ctype;  /* Type of the coordinates.                 */
 
 
   /* Output */
diff --git a/bin/mkprof/mkprof.c b/bin/mkprof/mkprof.c
index 1da73b7..131519a 100644
--- a/bin/mkprof/mkprof.c
+++ b/bin/mkprof/mkprof.c
@@ -117,9 +117,10 @@ saveindividual(struct mkonthread *mkp)
 {
   struct mkprofparams *p=mkp->p;
 
-  double crpix[2];
+  double *crpix;
   gal_data_t *data;
   long os=p->oversample;
+  size_t i, ndim=p->out->ndim;
   struct builtqueue *ibq=mkp->ibq;
   char *filename, *jobname, *outdir=p->outdir;
 
@@ -150,9 +151,11 @@ saveindividual(struct mkonthread *mkp)
     gal_fits_img_write(data, filename, NULL, PROGRAM_STRING);
   else
     {
-      /* Save the correct CRPIX values: */
-      crpix[0] = p->crpix[0] - os*(mkp->fpixel_i[0]-1);
-      crpix[1] = p->crpix[1] - os*(mkp->fpixel_i[1]-1);
+      /* Allocate space for the corrected crpix and fill it in. Both
+         `crpix' and `fpixel_i' are in FITS order. */
+      crpix=gal_data_malloc_array(GAL_TYPE_FLOAT64, ndim, __func__, "crpix");
+      for(i=0;i<ndim;++i)
+        crpix[0] = ((double *)(p->crpix->array))[0] - os*(mkp->fpixel_i[0]-1);
 
       /* Write the image. */
       gal_fits_img_write_corr_wcs_str(data, filename, p->wcsheader,
@@ -170,6 +173,7 @@ saveindividual(struct mkonthread *mkp)
       free(jobname);
     }
 
+
   /* Clean up. */
   if(p->kernel==NULL) free(filename);
 }
@@ -264,11 +268,12 @@ mkprof_build(void *inparam)
                                p->p[id]*DEGREESTORADIANS, mkp->width);
 
 
+
       /* Get the overlapping pixels using the starting points (NOT
          oversampled). */
       center[0]=p->x[id];
       center[1]=p->y[id];
-      gal_box_border_from_center(center, 2, mkp->width,
+      gal_box_border_from_center(center, p->out->ndim, mkp->width,
                                  ibq->fpixel_i, ibq->lpixel_i);
       mkp->fpixel_i[0]=ibq->fpixel_i[0];
       mkp->fpixel_i[1]=ibq->fpixel_i[1];
@@ -391,10 +396,11 @@ mkprof_write(struct mkprofparams *p)
   long os=p->oversample;
   int replace=p->replace;
   gal_data_t *out=p->out, *log;
+  size_t i, j, iw, jw, ii, jj, ow;
+  size_t w=p->dsize[ out->ndim - 1];         /* Number of rows. */
   struct builtqueue *ibq=NULL, *tbq;
   float *to, *from, *colend, *rowend;
   size_t complete=0, num=p->num, clog;
-  size_t i, j, iw, jw, ii, jj, w=p->naxes[0], ow;
 
 
   /* Write each image into the output array. */
@@ -428,17 +434,20 @@ mkprof_write(struct mkprofparams *p)
           i  = os * (ibq->fpixel_i[1]-1);
           j  = os * (ibq->fpixel_i[0]-1);
 
+
           /* Set the starting and ending points in the overlapping
              image. Note that oversampling has already been taken
-             into account in ibq->width. */
+             into account in ibq->imgwidth. */
           ow = ibq->imgwidth;
           ii = os * (ibq->fpixel_o[1]-1);
           jj = os * (ibq->fpixel_o[0]-1);
 
+
           /* Find the width of the overlapping region: */
           iw = os*(ibq->lpixel_i[1]-ibq->fpixel_i[1]+1);
           jw = os*(ibq->lpixel_i[0]-ibq->fpixel_i[0]+1);
 
+
           /* Write the overlap to the actual image. Instead of writing
              two for loops and summing all the row and column indexs
              for every pixel and each image, we use pointer arithmetic
@@ -580,10 +589,10 @@ mkprof(struct mkprofparams *p)
   pthread_attr_t attr;
   pthread_barrier_t b;
   struct mkonthread *mkp;
-  size_t i, *indexs, thrdcols;
   gal_list_str_t *comments=NULL;
-  size_t nt=p->cp.numthreads, nb;
-  long onaxes[2], os=p->oversample;
+  long *onaxes, os=p->oversample;
+  size_t i, fi, *indexs, thrdcols;
+  size_t nb, ndim=p->out->ndim, nt=p->cp.numthreads;
 
 
   /* Allocate the arrays to keep the thread and parameters for each
@@ -595,14 +604,22 @@ mkprof(struct mkprofparams *p)
     error(EXIT_FAILURE, errno, "%s: allocating %zu bytes for `mkp'",
           __func__, (nt-1)*sizeof *mkp);
 
+
   /* Distribute the different profiles for different threads. Note
      that one thread is left out for writing, while nt-1 are left
      for building. */
   gal_threads_dist_in_threads(p->num, nt, &indexs, &thrdcols);
 
-  /* onaxes are sides of the image without over-sampling. */
-  onaxes[0] = (p->naxes[0]-2*p->shift[0])/os + 2*p->shift[0]/os;
-  onaxes[1] = (p->naxes[1]-2*p->shift[1])/os + 2*p->shift[1]/os;
+
+  /* onaxes are sides of the image without over-sampling in FITS order. */
+  onaxes=gal_data_malloc_array(GAL_TYPE_LONG, ndim, __func__, "onaxes");
+  for(fi=0; fi < ndim; ++fi)
+    {
+      i=ndim-fi-1;
+      onaxes[fi] = ( ( p->dsize[i] - 2 * p->shift[i] ) / os
+                     + 2 * p->shift[i]/os );
+    }
+
 
   /* Build the profiles: */
   if(nt==1)
@@ -646,9 +663,11 @@ mkprof(struct mkprofparams *p)
           }
     }
 
+
   /* Write the created arrays into the image. */
   mkprof_write(p);
 
+
   /* Write the log file. */
   if(p->cp.log)
     {
@@ -659,6 +678,7 @@ mkprof(struct mkprofparams *p)
       gal_list_str_free(comments, 1);
     }
 
+
   /* If numthreads>1, then wait for all the jobs to finish and destroy
      the attribute and barrier. */
   if(nt>1)
@@ -670,7 +690,9 @@ mkprof(struct mkprofparams *p)
       pthread_mutex_destroy(&p->qlock);
     }
 
-  /* Free the allocated spaces. */
+
+  /* Clean up. */
   free(mkp);
   free(indexs);
+  free(onaxes);
 }
diff --git a/bin/mkprof/oneprofile.c b/bin/mkprof/oneprofile.c
index 0faeb09..6996d3b 100644
--- a/bin/mkprof/oneprofile.c
+++ b/bin/mkprof/oneprofile.c
@@ -406,8 +406,8 @@ oneprof_set_prof_params(struct mkonthread *mkp)
   size_t id=mkp->ibq->id;
 
   /* Fill in the profile independant parameters. */
-  p->x[id]       += p->shift[0]/p->oversample; /* Shifts were multiplied by */
-  p->y[id]       += p->shift[1]/p->oversample; /* `p->oversample' before.   */
+  p->x[id]       += p->shift[1]/p->oversample; /* Shifts were multiplied by */
+  p->y[id]       += p->shift[0]/p->oversample; /* `p->oversample' before.   */
   mkp->c          = cos( (90-p->p[id]) * DEGREESTORADIANS );
   mkp->s          = sin( (90-p->p[id]) * DEGREESTORADIANS );
   mkp->q          = p->q[id];
@@ -562,7 +562,7 @@ oneprofile_make(struct mkonthread *mkp)
 
 
   /* From this point on, the widths are the actual pixel
-     widths (with onversampling). */
+     widths (with oversampling). */
   mkp->width[0] *= os;
   mkp->width[1] *= os;
   mkp->ibq->imgwidth=mkp->width[0];
diff --git a/bin/mkprof/ui.c b/bin/mkprof/ui.c
index 29419f7..ecd1cd4 100644
--- a/bin/mkprof/ui.c
+++ b/bin/mkprof/ui.c
@@ -386,6 +386,94 @@ ui_parse_kernel(struct argp_option *option, char *arg,
 
 
 
+/* Parse options with values of a list of numbers. */
+void *
+ui_parse_numbers(struct argp_option *option, char *arg,
+                 char *filename, size_t lineno, void *junk)
+{
+  int i;
+  size_t nc;
+  double *darr;
+  gal_data_t *values;
+  char *str, sstr[GAL_OPTIONS_STATIC_MEM_FOR_VALUES];
+
+  /* We want to print the stored values. */
+  if(lineno==-1)
+    {
+      /* Set the pointer to the values dataset. */
+      values = *(gal_data_t **)(option->value);
+
+      /* Write each string into the output string */
+      nc=0;
+      darr=values->array;
+      for(i=0;i<values->size;++i)
+        {
+          if( nc > GAL_OPTIONS_STATIC_MEM_FOR_VALUES-100 )
+            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s so we "
+                  "can address the problem. The number of necessary "
+                  "characters in the statically allocated string has become "
+                  "too close to %d", __func__, PACKAGE_BUGREPORT,
+                  GAL_OPTIONS_STATIC_MEM_FOR_VALUES);
+          nc += sprintf(sstr+nc, "%g,", darr[i]);
+        }
+      sstr[nc-1]='\0';
+
+      /* Copy the string into a dynamically allocated space, because it
+         will be freed later.*/
+      gal_checkset_allocate_copy(sstr, &str);
+      return str;
+    }
+
+  /* We want to read the user's string. */
+  else
+    {
+      /* If the option is already set, just return. */
+      if(option->set) return NULL;
+
+      /* Read the values. */
+      values=gal_options_parse_list_of_numbers(arg, filename, lineno);
+
+      /* Put the values into the option. */
+      *(gal_data_t **)(option->value) = values;
+      return NULL;
+    }
+}
+
+
+
+
+
+/* Parse the mode to interpret the given coordinates. */
+void *
+ui_parse_coordinate_mode(struct argp_option *option, char *arg,
+                         char *filename, size_t lineno, void *junk)
+{
+  char *outstr;
+
+  /* We want to print the stored values. */
+  if(lineno==-1)
+    {
+      gal_checkset_allocate_copy( *(int *)(option->value)==MKPROF_MODE_IMG
+                                  ? "img" : "wcs", &outstr );
+      return outstr;
+    }
+  else
+    {
+      if      (!strcmp(arg, "img")) *(int *)(option->value)=MKPROF_MODE_IMG;
+      else if (!strcmp(arg, "wcs")) *(int *)(option->value)=MKPROF_MODE_WCS;
+      else
+        error_at_line(EXIT_FAILURE, 0, filename, lineno, "`%s' (value to "
+                      "`--mode') not recognized as a coordinate standard "
+                      "mode. Recognized values are `img' and `wcs'. This "
+                      "option is necessary to identify the nature of your "
+                      "input coordinates", arg);
+      return NULL;
+    }
+}
+
+
+
+
 
 
 
@@ -409,6 +497,8 @@ ui_parse_kernel(struct argp_option *option, char *arg,
 static void
 ui_read_check_only_options(struct mkprofparams *p)
 {
+  size_t i;
+
   /* When a no-merged image is to be created, type is necessary. */
   if( p->cp.type==GAL_TYPE_INVALID && p->nomerged==0)
     error(EXIT_FAILURE, 0, "an output type `--type' is necessary when a "
@@ -422,18 +512,20 @@ ui_read_check_only_options(struct mkprofparams *p)
      after this.*/
   if(p->kernel==NULL)
     {
-      if( ((p->xcol==NULL) + (p->ycol==NULL)) == 1 )
-        error(EXIT_FAILURE, 0, "only `%s' has been given, please also "
-              "specify a column for the position along the %s axis with "
-              "the `%s' option", p->xcol?"xcol":"ycol", p->xcol?"Y":"X",
-              p->xcol?"ycol":"xcol");
-
-      if( ((p->racol==NULL) + (p->deccol==NULL)) == 1 )
-        error(EXIT_FAILURE, 0, "only `%s' has been given, please also "
-              "specify a column for the position along the %s axis with "
-              "the `%s' option", p->racol?"racol":"deccol",
-              p->racol?"Dec":"RA", p->xcol?"deccol":"racol");
+      if(p->mode==0)
+        error(EXIT_FAILURE, 0, "the `--mode' option is necessary when "
+              "building profiles from a catalog. It can take two values: "
+              "`img' or `wcs' which specify how to interpret the "
+              "coordinate columns");
     }
+
+  /* Make sure no zero value is given for the `--naxis' option (only when
+     it is necessary). */
+  if(p->dsize && p->backname==NULL)
+    for(i=0;p->dsize[i]!=GAL_BLANK_SIZE_T;++i)
+      if(p->dsize[i]==0)
+        error(EXIT_FAILURE, 0, "values to `--naxes' option must not be "
+              "zero");
 }
 
 
@@ -534,16 +626,21 @@ static void
 ui_read_cols(struct mkprofparams *p)
 {
   int checkblank;
-  size_t counter=0, i;
   char *colname=NULL, **strarr;
-  gal_list_str_t *colstrs=NULL;
+  gal_list_str_t *colstrs=NULL, *ccol;
   gal_data_t *cols, *tmp, *corrtype=NULL;
-  char *ax1col=p->racol?p->racol:p->xcol;
-  char *ax2col=p->deccol?p->deccol:p->ycol;
-
-  /* Specify the order of columns. */
-  gal_list_str_add(&colstrs, ax1col, 0);
-  gal_list_str_add(&colstrs, ax2col, 0);
+  size_t i, counter=0, coordcounter=0, ndim=p->out->ndim;
+
+  /* Make sure the number of coordinate columns and number of dimensions in
+     outputs are the same. There is no problem if it is more than
+     `ndim'. In that case, the last values (possibly in configuration
+     files) will be ignored.*/
+  if( gal_list_str_number(p->ccol) < ndim )
+    error(EXIT_FAILURE, 0, "%zu coordinate columns (calls to `--coordcol') "
+          "given but output has %zu dimensions",
+          gal_list_str_number(p->ccol), p->out->ndim);
+
+  /* Put the columns a specific order to read. */
   gal_list_str_add(&colstrs, p->fcol, 0);
   gal_list_str_add(&colstrs, p->rcol, 0);
   gal_list_str_add(&colstrs, p->ncol, 0);
@@ -552,6 +649,19 @@ ui_read_cols(struct mkprofparams *p)
   gal_list_str_add(&colstrs, p->mcol, 0);
   gal_list_str_add(&colstrs, p->tcol, 0);
 
+  /* The coordinate columns might be different, So we'll add them to the
+     end (top of the list). */
+  ccol=p->ccol;
+  for(i=0;i<ndim;++i)
+    {
+      gal_list_str_add(&colstrs, ccol->v, 0);
+      ccol=ccol->next;
+    }
+
+  /* Reverse the order to make the column orders correspond to how we added
+     them here and avoid possible bugs. */
+  gal_list_str_reverse(&colstrs);
+
   /* Read the desired columns from the file. */
   cols=gal_table_read(p->catname, p->cp.hdu, colstrs, p->cp.searchin,
                       p->cp.ignorecase, p->cp.minmapsize);
@@ -575,19 +685,7 @@ ui_read_cols(struct mkprofparams *p)
          values into the `x' and `y' arrays even if they are RA/Dec. */
       switch(++counter)
         {
-        case 9:
-          colname="first axis position";
-          corrtype=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT64);
-          p->x=corrtype->array;
-          break;
-
-        case 8:
-          colname="second axis position";
-          corrtype=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT64);
-          p->y=corrtype->array;
-          break;
-
-        case 7:
+        case 1:
           if(tmp->type==GAL_TYPE_STRING)
             {
               p->f=gal_data_malloc_array(GAL_TYPE_INT32, p->num,
@@ -621,13 +719,13 @@ ui_read_cols(struct mkprofparams *p)
             }
           break;
 
-        case 6:
+        case 2:
           colname="radius (`rcol')";
           corrtype=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT32);
           p->r=corrtype->array;
           break;
 
-        case 5:
+        case 3:
           colname="index (`ncol')";
           corrtype=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT32);
           p->n=corrtype->array;
@@ -639,25 +737,39 @@ ui_read_cols(struct mkprofparams *p)
           p->p=corrtype->array;
           break;
 
-        case 3:
+        case 5:
           colname="axis ratio (`qcol')";
           corrtype=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT32);
           p->q=corrtype->array;
           break;
 
-        case 2:
+        case 6:
           colname="magnitude (`mcol')";
           corrtype=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT32);
           p->m=corrtype->array;
           checkblank=0;          /* Magnitude can be NaN: to mask regions. */
           break;
 
-        case 1:
+        case 7:
           colname="truncation (`tcol')";
           corrtype=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT32);
           p->t=corrtype->array;
           break;
 
+        case 8:
+        case 9:
+          ++coordcounter;
+          colname = ( counter==8
+                      ? "first coordinate column (`--coordcol')"
+                      : "second coordinate column (`--coordcol')" );
+          corrtype=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT64);
+          switch(counter)
+            {
+            case 8: p->x=corrtype->array; break;
+            case 9: p->y=corrtype->array; break;
+            }
+          break;
+
         /* If the index isn't recognized, then it is larger, showing that
            there was more than one match for the given criteria */
         default:
@@ -747,47 +859,132 @@ ui_prepare_columns(struct mkprofparams *p)
 
 
 
+/* To keep things clean, we'll do the WCS sanity checks in this small
+   function. If everything is ok, this function will return 0 (so an if
+   condition won't be executed). If any of the necessary inputs aren't
+   given, it will return 1. */
+static int
+ui_wcs_sanity_check(struct mkprofparams *p)
+{
+  size_t ndim=p->out->ndim;
+
+  if(p->crpix)
+    {
+      if(p->crpix->size!=ndim)
+        error(EXIT_FAILURE, 0, "%zu values given to `--crpix'. This must be "
+              "the same as the output dimension (%zu)", p->crpix->size, ndim);
+      return 0;
+    }
+  else return 1;
+
+  if(p->crval)
+    {
+      if(p->crval->size!=ndim)
+        error(EXIT_FAILURE, 0, "%zu values given to `--crval'. This must be "
+              "the same as the output dimension (%zu)", p->crval->size, ndim);
+      return 0;
+    }
+  else return 1;
+
+  if(p->cdelt)
+    {
+      if(p->cdelt->size!=ndim)
+        error(EXIT_FAILURE, 0, "%zu values given to `--cdelt'. This must be "
+              "the same as the output dimension (%zu)", p->cdelt->size, ndim);
+      return 0;
+    }
+  else return 1;
+
+  if(p->pc)
+    {
+      if(p->pc->size!=ndim*ndim)
+        error(EXIT_FAILURE, 0, "%zu values given to `--pc'. This must be "
+              "the square as the output dimension (%zu)", p->pc->size,
+              ndim*ndim);
+      return 0;
+    }
+  else return 1;
+
+  if(p->cunit)
+    {
+      if(p->cunit->size!=ndim)
+        error(EXIT_FAILURE, 0, "%zu values given to `--cunit'. This must be "
+              "the same as the output dimension (%zu)", p->cunit->size, ndim);
+      return 0;
+    }
+  else return 1;
+
+  if(p->ctype)
+    {
+      if(p->ctype->size!=ndim)
+        error(EXIT_FAILURE, 0, "%zu values given to `--ctype'. This must be "
+              "the same as the output dimension (%zu)", p->ctype->size, ndim);
+      return 0;
+    }
+  else return 1;
+}
+
+
+
+
+
 static void
 ui_prepare_wcs(struct mkprofparams *p)
 {
   int status;
   struct wcsprm *wcs;
-  long os=p->oversample;
+  char **cunit, **ctype;
+  size_t i, ndim=p->out->ndim;
+  double *crpix, *crval, *cdelt, *pc;
+
 
   /* If the WCS structure is already set, then return. */
   if(p->out->wcs) return;
 
+
+  /* Check and initialize the WCS information. If any of the necessary WCS
+     parameters are missing, then don't build any WCS. */
+  if( ui_wcs_sanity_check(p) ) return;
+  crpix = p->crpix->array;
+  crval = p->crval->array;
+  cdelt = p->cdelt->array;
+  pc    = p->pc->array;
+  cunit = p->cunit->array;
+  ctype = p->ctype->array;
+
+
   /* Allocate the memory necessary for the wcsprm structure. */
   errno=0;
   wcs=p->out->wcs=malloc(sizeof *wcs);
   if(wcs==NULL)
     error(EXIT_FAILURE, errno, "%zu for wcs in preparewcs", sizeof *wcs);
 
+
   /* Initialize the structure (allocate all its internal arrays). */
   wcs->flag=-1;
-  if( (status=wcsini(1, 2, wcs)) )
+  if( (status=wcsini(1, ndim, wcs)) )
     error(EXIT_FAILURE, 0, "wcsini error %d: %s",
           status, wcs_errmsg[status]);
 
-  /* Correct the CRPIX values based on oversampling and shifting. */
-  p->crpix[0] = p->crpix[0]*os + p->shift[0] - os/2;
-  p->crpix[1] = p->crpix[1]*os + p->shift[1] - os/2;
 
   /* Fill in all the important WCS structure parameters. */
   wcs->altlin   = 0x1;
   wcs->equinox  = 2000.0f;
-  wcs->crpix[0] = p->crpix[0];
-  wcs->crpix[1] = p->crpix[1];
-  wcs->crval[0] = p->crval[0];
-  wcs->crval[1] = p->crval[1];
-  wcs->pc[0]    = -1.0f;
-  wcs->pc[3]    = 1.0f;
-  wcs->pc[1]    = wcs->pc[2]=0.0f;
-  wcs->cdelt[0] = wcs->cdelt[1]=p->resolution/3600;
-  strcpy(wcs->cunit[0], "deg");
-  strcpy(wcs->cunit[1], "deg");
-  strcpy(wcs->ctype[0], "RA---TAN");
-  strcpy(wcs->ctype[1], "DEC--TAN");
+  for(i=0;i<ndim;++i)
+    {
+      /* IMPORTANT: At this point, we don't want the WCS to be over-sampled
+         because if the user has given RA and Dec for the profiles, they
+         need to be converted to non-oversampled and shifted image
+         coordinates. After the conversion (in `ui_finalize_coordinates')
+         we are going to correct for the oversampling in the WCS.*/
+      wcs->crpix[i] = crpix[i];
+      wcs->crval[i] = crval[i];
+      wcs->cdelt[i] = cdelt[i];
+      strcpy(wcs->cunit[i], cunit[i]);
+      strcpy(wcs->ctype[i], ctype[i]);
+    }
+  for(i=0;i<ndim*ndim;++i) wcs->pc[i]=pc[i];
+
 
   /* Set up the wcs structure with the constants defined above. */
   status=wcsset(wcs);
@@ -803,11 +1000,11 @@ ui_prepare_wcs(struct mkprofparams *p)
 static void
 ui_prepare_canvas(struct mkprofparams *p)
 {
-  int status=0;
   float *f, *ff;
   double truncr;
   long width[2]={1,1};
-  size_t i, ndim, dsize[2];
+  int status=0, setshift=0;
+  size_t i, ndim, nshift=0, *dsize=NULL;
 
   /* If a background image is specified, then use that as the output
      image to build the profiles over. */
@@ -825,7 +1022,8 @@ ui_prepare_canvas(struct mkprofparams *p)
 
       /* Read in the background image and its coordinates, note that when
          no merged image is desired, we just need the WCS information of
-         the background image. */
+         the background image. So `ndim==0' and what `dsize' points to is
+         irrelevant. */
       if(p->nomerged)
         p->out=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, 0, dsize, NULL,
                               1, p->cp.minmapsize, NULL, NULL, NULL);
@@ -835,8 +1033,19 @@ ui_prepare_canvas(struct mkprofparams *p)
           p->out=gal_fits_img_read_to_type(p->backname, p->backhdu,
                                            GAL_TYPE_FLOAT32,
                                            p->cp.minmapsize);
-          p->naxes[0]=p->out->dsize[1];
-          p->naxes[1]=p->out->dsize[0];
+          ndim=p->out->ndim;
+
+          /* Currently this only works on 2D images. */
+          if(p->out->ndim!=2)
+            error(EXIT_FAILURE, 0, "currently only works on 2D images");
+
+          /* If p->dsize was given as an option, free it. */
+          if( p->dsize ) free(p->dsize);
+
+          /* Write the size of the background image into `dsize'. */
+          p->dsize=gal_data_malloc_array(GAL_TYPE_SIZE_T, p->out->ndim,
+                                         __func__, "p->dsize");
+          for(i=0;i<p->out->ndim;++i) p->dsize[i] = p->out->dsize[i];
 
           /* Set all pixels to zero if the user wanted a clear canvas. */
           if(p->clearcanvas)
@@ -846,7 +1055,9 @@ ui_prepare_canvas(struct mkprofparams *p)
       /* When a background image is specified, oversample must be 1 and
          there is no shifts. */
       p->oversample=1;
-      p->shift[0]=p->shift[1]=0;
+      if(p->shift) free(p->shift);
+      p->shift=gal_data_calloc_array(GAL_TYPE_SIZE_T, p->out->ndim,
+                                     __func__, "p->shift (1)");
 
       /* Read the WCS structure of the background image. */
       p->out->wcs=gal_wcs_read(p->backname, p->backhdu, 0, 0, &p->out->nwcs);
@@ -854,13 +1065,31 @@ ui_prepare_canvas(struct mkprofparams *p)
     }
   else
     {
-      /* If any of xshift or yshift is non-zero, the other should be too!
-         Note that conditional operators return 1 if true and 0 if false,
-         so if one is non-zero while the other is zero, then sum will be
-         1. Otherwise the sum will either be 0 or 2.*/
-      switch ( (p->shift[0]!=0) + (p->shift[1]!=0) )
+      /* Get the number of dimensions. */
+      ndim=0; for(i=0;p->dsize[i]!=GAL_BLANK_SIZE_T;++i) ++ndim;
+      if(ndim!=2)
+        error(EXIT_FAILURE, 0, "currently only 2D images are usable, you "
+              "have provided %zu values for `--naxis'", ndim);
+
+
+      /* If any of the shift elements are zero, the others should be too!*/
+      if(p->shift && p->shift[0] && p->shift[1])
+        {
+          /* Multiply the shift by the over-sample. */
+          for(i=0;p->shift[i]!=GAL_BLANK_SIZE_T;++i)
+            {
+              ++nshift;
+              p->shift[i] *= p->oversample;
+            }
+
+          /* Make sure it has the same number of elements as naxis. */
+          if(ndim!=nshift)
+            error(EXIT_FAILURE, 0, "%zu and %zu elements given to `--ndim' "
+                  "and `--shift' respectively. These two numbers must be the "
+                  "same", ndim, nshift);
+        }
+      else
         {
-        case 0:
           /* `prepforconv' is only valid when xshift and yshift are both
              zero. Also, a PSF profile should exist in the image. */
           if(p->prepforconv)
@@ -872,57 +1101,55 @@ ui_prepare_canvas(struct mkprofparams *p)
                     /* Calculate the size of the box holding the PSF. Note:
 
                        - For the Moffat and Gaussian profiles, the radius
-                       columns is actually the FWHM which is actually the
+                       column is actually the FWHM which is actually the
                        diameter, not radius. So we have to divide it by
                        half.
 
                        - encloseellipse outputs the total width, we only want
                        half of it for the shift. */
+                    setshift=1;
                     truncr = p->tunitinp ? p->t[i] : p->t[i] * p->r[i]/2;
                     gal_box_ellipse_in_box(truncr, p->q[i]*truncr,
                                            p->p[i]*DEGREESTORADIANS, width);
-                    p->shift[0]  = (width[0]/2)*p->oversample;
-                    p->shift[1]  = (width[1]/2)*p->oversample;
                   }
-            }
-          break;
-
-        case 1:
-          error(EXIT_FAILURE, 0, "at least one of `--xshift` (`-X`) or "
-                "`--yshift` (`-Y`) are zero, they must either both be zero "
-                "or both given a positive value");
-          break;
-
-        case 2:
-          p->shift[0] *= p->oversample;
-          p->shift[1] *= p->oversample;
-          break;
 
-        default:
-          error(EXIT_FAILURE, 0, "a bug in ui_prepare_canvas! In checks "
-                "for shifts. Please contact us at %s so we can fix it",
-                PACKAGE_BUGREPORT);
+              /* Either set the shifts to zero or to the values set from
+                 the PSF. Note that the user might have given any number of
+                 shifts (from zero). So, we'll just free it and reset
+                 it. */
+              if(p->shift) free(p->shift);
+              p->shift=gal_data_calloc_array(GAL_TYPE_SIZE_T, p->out->ndim,
+                                             __func__, "p->shift (2)");
+              if(setshift)
+                {
+                  p->shift[0]  = (width[0]/2)*p->oversample;
+                  p->shift[1]  = (width[1]/2)*p->oversample;
+                }
+            }
         }
 
+      /* If shift has not been set until now, set it. */
+      if(p->shift==NULL)
+        p->shift=gal_data_calloc_array(GAL_TYPE_SIZE_T, ndim, __func__,
+                                       "p->shift (3)");
+
       /* Prepare the sizes of the final merged image (if it is to be
-         made). */
+         made). Note that even if we don't want a merged image, we still
+         need its WCS structure. */
       if(p->nomerged)
         ndim=0;
       else
         {
-          /* Sanity check */
-          if(p->naxes[0]==0 || p->naxes[1]==0)
-            error(EXIT_FAILURE, 0, "No final merged image size is specified, "
-                  "please use the `--naxis1', and `--naxis2' options to "
-                  "specify the respective sizes");
-
-          /* Set the final merged image size. Note that even if we don't
-             want a merged image, we still need its WCS structure.*/
-          p->naxes[0] = (p->naxes[0] * p->oversample) + (2 * p->shift[0]);
-          p->naxes[1] = (p->naxes[1] * p->oversample) + (2 * p->shift[1]);
-          dsize[0]    = p->naxes[1];
-          dsize[1]    = p->naxes[0];
-          ndim        = 2;
+          ndim=0;
+          for(i=0;p->dsize[i]!=GAL_BLANK_SIZE_T;++i)
+            {
+              /* Count the number of dimensions. */
+              ++ndim;
+
+              /* Correct dsize. */
+              p->dsize[i] = (p->dsize[i]*p->oversample) + (2*p->shift[i]);
+            }
+          dsize = p->dsize;
         }
 
       /* Make the output structure. */
@@ -969,13 +1196,15 @@ ui_prepare_canvas(struct mkprofparams *p)
 static void
 ui_finalize_coordinates(struct mkprofparams *p)
 {
-  size_t i;
   double *x=NULL, *y=NULL;
+  uint8_t os=p->oversample;
+  size_t i, ndim=p->out->ndim;
+  double *cdelt=p->out->wcs->cdelt, *crpix=p->out->wcs->crpix;
 
   /* When the user specified RA and Dec columns, the respective values
      where stored in the `p->x' and `p->y' arrays. So before proceeding, we
      need to change them into actual image coordinates. */
-  if(p->racol)
+  if(p->mode==MKPROF_MODE_WCS)
     {
       /* Note that we read the RA and Dec columns into the `p->x' and `p->y'
          arrays temporarily before. Here, we will convert them, free the old
@@ -997,15 +1226,18 @@ ui_finalize_coordinates(struct mkprofparams *p)
       p->y=y;
     }
 
-
   /* Correct the WCS scale. Note that when the WCS is read from a
      background image, oversample is set to 1. This is done here because
      the conversion of WCS to pixel coordinates needs to be done with the
-     non-over-sampled image. */
-  p->out->wcs->cdelt[0] /= p->oversample;
-  p->out->wcs->cdelt[1] /= p->oversample;
-
-
+     non-over-sampled image.*/
+  for(i=0;i<p->out->ndim;++i)
+    {
+      /* Oversampling has already been applied in `p->shift'. Also note
+         that shift is in the C dimension ordring, while crpix is in FITS
+         ordering. */
+      crpix[i]  = crpix[i]*os + p->shift[ndim-i-1] - os/2;
+      cdelt[i] /= os;
+    }
 
   /* For a sanity check:
   printf("\nui_finalize_coordinates sanity check:\n");
@@ -1076,12 +1308,12 @@ ui_preparations(struct mkprofparams *p)
       p->individual=1;
     }
 
-  /* Read in all the columns. */
-  ui_prepare_columns(p);
-
   /* Prepare the output canvas. */
   ui_prepare_canvas(p);
 
+  /* Read in all the columns. */
+  ui_prepare_columns(p);
+
   /* Read the (possible) RA/Dec inputs into X and Y for the builder.*/
   ui_finalize_coordinates(p);
 
diff --git a/bin/mkprof/ui.h b/bin/mkprof/ui.h
index c7361cb..e11cd3e 100644
--- a/bin/mkprof/ui.h
+++ b/bin/mkprof/ui.h
@@ -31,16 +31,15 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
    Available letters (-V which is used by GNU is also removed):
 
-   a b d g j l n u v
-   A G H J L O Q W
+   a b d g j l n u v y
+   A G H J L O Q W Y
 */
 enum option_keys_enum
 {
   /* With short-option version. */
   UI_KEY_BACKGROUND      = 'k',
   UI_KEY_BACKHDU         = 'B',
-  UI_KEY_NAXIS1          = 'x',
-  UI_KEY_NAXIS2          = 'y',
+  UI_KEY_NAXIS           = 'x',
   UI_KEY_CLEARCANVAS     = 'C',
   UI_KEY_KERNEL          = 'E',
   UI_KEY_OVERSAMPLE      = 's',
@@ -49,8 +48,7 @@ enum option_keys_enum
   UI_KEY_NUMRANDOM       = 'r',
   UI_KEY_TOLERANCE       = 't',
   UI_KEY_TUNITINP        = 'p',
-  UI_KEY_XSHIFT          = 'X',
-  UI_KEY_YSHIFT          = 'Y',
+  UI_KEY_SHIFT           = 'X',
   UI_KEY_PREPFORCONV     = 'c',
   UI_KEY_ZEROPOINT       = 'z',
   UI_KEY_CIRCUMWIDTH     = 'w',
@@ -61,10 +59,8 @@ enum option_keys_enum
   /* Only with long version. */
   UI_KEY_PSFINIMG        = 1000,
   UI_KEY_MAGATPEAK,
-  UI_KEY_XCOL,
-  UI_KEY_YCOL,
-  UI_KEY_RACOL,
-  UI_KEY_DECCOL,
+  UI_KEY_MODE,
+  UI_KEY_CCOL,
   UI_KEY_FCOL,
   UI_KEY_RCOL,
   UI_KEY_NCOL,
@@ -72,11 +68,12 @@ enum option_keys_enum
   UI_KEY_QCOL,
   UI_KEY_MCOL,
   UI_KEY_TCOL,
-  UI_KEY_CRPIX1,
-  UI_KEY_CRPIX2,
-  UI_KEY_CRVAL1,
-  UI_KEY_CRVAL2,
-  UI_KEY_RESOLUTION,
+  UI_KEY_CRPIX,
+  UI_KEY_CRVAL,
+  UI_KEY_CDELT,
+  UI_KEY_PC,
+  UI_KEY_CUNIT,
+  UI_KEY_CTYPE,
 };
 
 
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index fdd0cb5..b901403 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -14872,22 +14872,24 @@ reading the input, so nothing will happen to your 
input file).
 
 @item -B STR/INT
 @itemx --backhdu=STR/INT
-The header data unit (HDU) of the file given to
+The header data unit (HDU) of the file given to @option{--background}.
 
address@hidden -x INT
address@hidden --naxis1=INT
-The number of pixels in the output image along the first FITS axis
-(horizontal when viewed in SAO ds9). This is before over-sampling. For
-example if you call MakeProfiles with @option{--naxis1=100 --oversample=5}
-(assuming no shift due for later convolution), then the final image size
-along the first axis will be 500. If a background image is specified, any
-possible value to this option is ignored.
address@hidden -x INT,INT
address@hidden --naxis=INT,INT
+The number of pixels along each dimension axis of the output in FITS
+order. This is before over-sampling. For example if you call MakeProfiles
+with @option{--naxis=100,150 --oversample=5} (assuming no shift due for
+later convolution), then the final image size along the first axis will be
+500 by 750 pixels. Fractions are acceptable as values for each dimension,
+however, they must reduce to an integer, so @option{--naxis=150/3,300/3} is
+acceptable but @option{--naxis=150/4,300/4} is not.
 
address@hidden -y INT
address@hidden --naxis2=INT
-The number of pixels in the output image along the second FITS axis
-(vertical when viewed in SAO ds9), see the explanation for
address@hidden
+When viewing a FITS image in DS9, the first FITS dimension is in the
+horizontal direction and the second is vertical. As an example, the image
+created with the example above will have 500 pixels horizontally and 750
+pixels vertically.
+
+If a background image is specified, this option is ignored.
 
 @item -s INT
 @itemx --oversample=INT
@@ -14972,18 +14974,14 @@ default, the truncation column is considered to be in 
units of the
 radial parameters of the profile (@option{--rcol}). Read it as
 `t-unit-in-p' for `truncation unit in pixels'.
 
address@hidden -X INT
address@hidden --xshift=INT
-Shift all the profiles and enlarge the image along the first FITS axis, see
address@hidden in @ref{If convolving afterwards}. This is useful when you want
-to convolve the image afterwards. If you are using an external PSF, be sure
-to oversample it to the same scale used for creating the mock images. If a
-background image is specified, any possible value to this option is
-ignored.
-
address@hidden -Y INT
address@hidden --yshift=INT
-Similar to @option{--xshift} for the second FITS axis.
address@hidden -X INT,INT
address@hidden --shift=INT,INT
+Shift all the profiles and enlarge the image along each dimension. To
+better understand this option, please see @mymath{n} in @ref{If convolving
+afterwards}. This is useful when you want to convolve the image
+afterwards. If you are using an external PSF, be sure to oversample it to
+the same scale used for creating the mock images. If a background image is
+specified, any possible value to this option is ignored.
 
 @item -c
 @itemx --prepforconv
@@ -15050,7 +15048,7 @@ profile. However, when using flat profiles with the
 @code{0.0} value as the flat profile's pixel value.
 
 @item -C
address@hidden --clearcanvas
address@hidden --clearcanvas
 When an input image is specified (with the @option{--background} option,
 set all its pixels to 0.0 immediately after reading it into
 memory. Effectively, this will allow you to use all its properties
@@ -15081,6 +15079,19 @@ column number, where counting starts from zero.
 
 @table @option
 
address@hidden --mode=STR
+Interpret the center position columns in image or WCS coordinates. This
+option thus accepts only two values: @option{img} and @option{wcs}. It is
+mandatory when a catalog is being used.
+
address@hidden --ccol=STR/INT
+Center coordinate column for each dimension. This option must be called two
+times to define the center coordinates in an image. For example
address@hidden and @option{--ccol=DEC} (along with @option{--mode=wcs})
+will inform MakeProfiles to look into the catalog columns named @option{RA}
+and @option{DEC} for the Right Ascension and Declination of the profile
+centers.
+
 @item --fcol=INT/STR
 The functional form of the profile with one of the values below depending
 on the desired profile. The column can contain either the numeric codes
@@ -15113,27 +15124,6 @@ value will be used for all pixels between the 
truncation radius
 @option{--circumwidth}).
 @end itemize
 
address@hidden --xcol=STR/INT
-The center of the profiles along the first FITS axis (horizontal when
-viewed in SAO ds9). See the explanations for @option{--racol} for
-precedence when both image and WCS coordinate columns are given.
-
address@hidden --ycol=STR/INT
-The center of the profiles along the second FITS axis (vertical when viewed
-in SAO ds9). Similar to @option{--xcol}.
-
address@hidden --racol=STR/INT
-The profile center's right ascension. Along with @option{--deccol}, these
-WCS coordinate columns are not mandatory. If they are not given, the
address@hidden and @option{--ycol} options will be used to specify the
-profile's central position and vice-versa. However, if image coordinate
-columns (@option{--xcol} and @option{--ycol}) and WCS coordinate columns
-(@option{--racol} and @option{--deccol}) are given, the WCS coordinate
-columns take precedence and image coordinate columns will be ignored.
-
address@hidden --deccol=STR/INT
-The profile center's declination. Similar to @option{--racol}.
-
 @item --rcol=STR/INT
 The radius parameter of the profiles. Effective radius (@mymath{r_e}) if
 S@'ersic, FWHM if Moffat or Gaussian.
@@ -15198,26 +15188,57 @@ your catalog.
 @end table
 
 @noindent
-WCS:
+The options below can be used to define the world coordinate system (WCS)
+properties of the MakeProfiles outputs. The option names are delibarately
+chosen to be the same as the FITS standard WCS keywords. See Section 8 of
address@hidden://doi.org/10.1051/0004-6361/201015362, Pence et al [2010]} for a
+short introduction to WCS in the FITS address@hidden world
+coordinate standard in FITS is a very beatiful and powerful concept to
+link/associate datasets with the outside world (other datasets). The
+description in the FITS standard (link above) only touches the tip of the
+ice-burg. To learn more please see
address@hidden://doi.org/10.1051/0004-6361:20021326, Greisen and Calabretta
+[2002]}, @url{https://doi.org/10.1051/0004-6361:20021327, Calabretta and
+Greisen [2002]}, @url{https://doi.org/10.1051/0004-6361:20053818, Greisen
+et al. [2006]}, and
address@hidden://www.atnf.csiro.au/people/mcalabre/WCS/dcs_20040422.pdf,
+Calabretta et al.}}.
+
+If you look into the headers of a FITS image with WCS for example you will
+see all these names but in uppercase and with numbers to represent the
+dimensions, for example @code{CRPIX1} and @code{PC2_1}. You can see the
+FITS headers with Gnuastro's @ref{Fits} program using a command like this:
address@hidden astfits -p image.fits}.
 
 @table @option
 
address@hidden --crpix1=FLT
-The pixel coordinates of the WCS reference point on the first (horizontal)
-FITS axis (counting from 1).
address@hidden --crpix=FLT,FLT
+The pixel coordinates of the WCS reference point. Fractions are acceptable
+for the values of this option.
 
address@hidden --crpix2=FLT
-The pixel coordinates of the WCS reference point on the second (vertical)
-FITS axis (counting from 1).
address@hidden --crval=FLT,FLT
+The WCS coordinates of the Reference point. Fractions are acceptable for
+the values of this option.
 
address@hidden --crval1=FLT
-The Right Ascension (RA) of the reference point.
address@hidden --cdelt=FLT,FLT
+The resolution (size of one data-unit or pixel in WCS units) of the
+non-oversampled dataset. Fractions are acceptable for the values of this
+option.
+
address@hidden --pc=FLT,FLT,FLT,FLT
+The PC matrix of the WCS rotation, see the FITS standard (link above) to
+better understand the PC matrix.
 
address@hidden --crval2=FLT
-The Declination of the reference point.
address@hidden --cunit=STR,STR
+The units of each WCS axis, for example @code{deg}. Note that these values
+are part of the FITS standard (link above). MakeProfiles won't complain if
+you use non-standard values, but later usage of them might cause trouble.
 
address@hidden --resolution=FLT
-The resolution of the non-oversampled image in units of arcseconds/pixel.
address@hidden --ctype=STR,STR
+The type of each WCS axis, for example @code{RA---TAN} and
address@hidden Note that these values are part of the FITS standard (link
+above). MakeProfiles won't complain if you use non-standard values, but
+later usage of them might cause trouble.
 
 @end table
 
@@ -17994,6 +18015,11 @@ example). If the given pointer is not the start of an 
allocated block of
 memory or it is used in multiple datasets, be sure to set it to @code{NULL}
 (with @code{data->array=NULL}) before cleaning up with
 @code{gal_data_free_contents}.
+
address@hidden may be zero. In this case no allocation will occur,
address@hidden>array} and @code{data->dsize} will be set to @code{NULL} and
address@hidden>size} will be zero. However (when necessary) @code{dsize} must
+not have any zero values (a dimension of length zero is not defined).
 @end deftypefun
 
 @deftypefun {void *} gal_data_alloc (void @code{*array}, uint8_t @code{type}, 
size_t @code{ndim}, size_t @code{*dsize}, struct wcsprm @code{*wcs}, int 
@code{clear}, size_t @code{minmapsize}, char @code{*name}, char @code{*unit}, 
char @code{*comment})
diff --git a/lib/box.c b/lib/box.c
index d7d3386..ae5e708 100644
--- a/lib/box.c
+++ b/lib/box.c
@@ -62,8 +62,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
    Once you find the "t", put it in (2) for the respective coordinate
    and you will find the distance (about the center of the ellipse
-   that encloses the whole ellipse.
-*/
+   that encloses the whole ellipse. */
 void
 gal_box_ellipse_in_box(double a, double b, double theta_rad, long *width)
 {
diff --git a/lib/fits.c b/lib/fits.c
index abb30cd..4cddcc6 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -1764,10 +1764,10 @@ gal_fits_img_write_corr_wcs_str(gal_data_t *input, char 
*filename,
      original version, we just want to change the copied version. */
   if(crpix)
     {
-      fits_update_key(fptr, TDOUBLE, "CRPIX1", &crpix[0],
-                      NULL, &status);
-      fits_update_key(fptr, TDOUBLE, "CRPIX2", &crpix[1],
-                      NULL, &status);
+      fits_update_key(fptr, TDOUBLE, "CRPIX1", &crpix[0], NULL, &status);
+      fits_update_key(fptr, TDOUBLE, "CRPIX2", &crpix[1], NULL, &status);
+      if(input->ndim==3)
+        fits_update_key(fptr, TDOUBLE, "CRPIX3", &crpix[2], NULL, &status);
       gal_fits_io_error(status, NULL);
     }
 
diff --git a/lib/gnuastro-internal/options.h b/lib/gnuastro-internal/options.h
index 9a9f974..9dddd10 100644
--- a/lib/gnuastro-internal/options.h
+++ b/lib/gnuastro-internal/options.h
@@ -236,11 +236,6 @@ 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);
 
-gal_data_t *
-gal_options_parse_list_of_numbers(char *string, char *filename,
-                                  size_t lineno);
-
-
 
 
 /**********************************************************************/
@@ -266,6 +261,18 @@ void *
 gal_options_read_tableformat(struct argp_option *option, char *arg,
                              char *filename, size_t lineno, void *junk);
 
+gal_data_t *
+gal_options_parse_list_of_numbers(char *string, char *filename,
+                                  size_t lineno);
+
+gal_data_t *
+gal_options_parse_csv_strings_raw(char *string, char *filename,
+                                  size_t lineno);
+
+void *
+gal_options_parse_csv_strings(struct argp_option *option, char *arg,
+                              char *filename, size_t lineno, void *junk);
+
 void *
 gal_options_parse_sizes_reverse(struct argp_option *option, char *arg,
                                 char *filename, size_t lineno, void *params);
diff --git a/lib/options.c b/lib/options.c
index e832487..c67c52b 100644
--- a/lib/options.c
+++ b/lib/options.c
@@ -33,6 +33,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <gnuastro/list.h>
 #include <gnuastro/data.h>
 #include <gnuastro/table.h>
+#include <gnuastro/blank.h>
 #include <gnuastro/arithmetic.h>
 
 #include <gnuastro-internal/timing.h>
@@ -155,135 +156,6 @@ options_get_home()
 
 
 
-/* The input to this function is a string of any number of numbers
-   separated by a comma (`,') and possibly containing fractions, for
-   example: `1,2/3, 4.95'. The output `gal_data_t' contains the array of
-   given values in `double' type. You can read the number from its `size'
-   element. */
-gal_data_t *
-gal_options_parse_list_of_numbers(char *string, char *filename, size_t lineno)
-{
-  size_t i, num=0;
-  gal_data_t *out;
-  char *c=string, *tailptr;
-  gal_list_f64_t *list=NULL, *tdll;
-  double numerator=NAN, denominator=NAN, tmp;
-
-
-  /* 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;
-
-  /* Go through the input character by character. */
-  while(string && *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'",
-                          string);
-          gal_list_f64_add(&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'", string);
-          ++c;
-          break;
-
-        /* Extra dot is an error (cases like 2.5.5). Valid `.'s will be
-           read by `strtod'. */
-        case '.':
-          error_at_line(EXIT_FAILURE, 0, filename, lineno, "extra `.' in "
-                        "`%s'", string);
-          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'", c, string);
-
-          /* 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;
-        }
-    }
-
-
-  /* If the last number wasn't finished by a `,', add the read value to the
-     list */
-  if( !isnan(numerator) )
-    {
-      ++num;
-      gal_list_f64_add(&list, isnan(denominator)
-                       ? numerator : numerator/denominator);
-    }
-
-
-  /* Allocate the output data structure and fill it up. */
-  if(num)
-    {
-      i=num;
-      out=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &num, NULL, 0,
-                         minmapsize, NULL, NULL, NULL);
-      for(tdll=list;tdll!=NULL;tdll=tdll->next)
-        ((double *)(out->array))[--i]=tdll->v;
-    }
-  else
-    {
-      /* It is not possible to allocate a dataset with a size of 0 along
-         any dimension (in C it's possible, but conceptually it isn't). So,
-         we'll allocate space for one element, then free it. */
-      i=1;
-      out=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &i, NULL, 0,
-                         minmapsize, NULL, NULL, NULL);
-      out->size=out->dsize[0]=0;
-      free(out->array);
-      out->array=NULL;
-    }
-
-
-  /* Clean up and return. */
-  gal_list_f64_free(list);
-  return out;
-}
-
-
-
-
-
 
 
 
@@ -530,11 +402,284 @@ gal_options_read_tableformat(struct argp_option *option, 
char *arg,
 
 
 
+/* The input to this function is a string of any number of numbers
+   separated by a comma (`,') and possibly containing fractions, for
+   example: `1,2/3, 4.95'. The output `gal_data_t' contains the array of
+   given values in `double' type. You can read the number from its `size'
+   element. */
+gal_data_t *
+gal_options_parse_list_of_numbers(char *string, char *filename, size_t lineno)
+{
+  size_t i, num=0;
+  gal_data_t *out;
+  char *c=string, *tailptr;
+  gal_list_f64_t *list=NULL, *tdll;
+  double numerator=NAN, denominator=NAN, tmp;
+
+
+  /* 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;
+
+  /* Go through the input character by character. */
+  while(string && *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'",
+                          string);
+          gal_list_f64_add(&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'", string);
+          ++c;
+          break;
+
+        /* Extra dot is an error (cases like 2.5.5). Valid `.'s will be
+           read by `strtod'. */
+        case '.':
+          error_at_line(EXIT_FAILURE, 0, filename, lineno, "extra `.' in "
+                        "`%s'", string);
+          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'", c, string);
+
+          /* 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;
+        }
+    }
+
+
+  /* If the last number wasn't finished by a `,', add the read value to the
+     list */
+  if( !isnan(numerator) )
+    {
+      ++num;
+      gal_list_f64_add(&list, isnan(denominator)
+                       ? numerator : numerator/denominator);
+    }
+
+
+  /* Allocate the output data structure and fill it up. */
+  if(num)
+    {
+      i=num;
+      out=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &num, NULL, 0,
+                         minmapsize, NULL, NULL, NULL);
+      for(tdll=list;tdll!=NULL;tdll=tdll->next)
+        ((double *)(out->array))[--i]=tdll->v;
+    }
+  else
+    {
+      /* It is not possible to allocate a dataset with a size of 0 along
+         any dimension (in C it's possible, but conceptually it isn't). So,
+         we'll allocate space for one element, then free it. */
+      i=1;
+      out=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, &i, NULL, 0,
+                         minmapsize, NULL, NULL, NULL);
+      out->size=out->dsize[0]=0;
+      free(out->array);
+      out->array=NULL;
+    }
+
+
+  /* Clean up and return. */
+  gal_list_f64_free(list);
+  return out;
+}
+
+
+
+
+
+/* The input to this function is a string of any number of strings
+   separated by a comma (`,') for example: `a,abc,abcd'. The output
+   `gal_data_t' contains the array of given strings. You can read the
+   number of inputs from its `size' element. */
+gal_data_t *
+gal_options_parse_csv_strings_raw(char *string, char *filename, size_t lineno)
+{
+  size_t i, num;
+  gal_data_t *out;
+  char *c=string, *str=NULL;
+  gal_list_str_t *list=NULL, *tstrll=NULL;
+
+
+  /* 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;
+
+
+  /* Go through the input character by character. */
+  while(string && *c!='\0')
+    {
+      switch(*c)
+        {
+        /* Comma marks the transition to the next string. */
+        case ',':
+          if(str==NULL)
+            error_at_line(EXIT_FAILURE, 0, filename, lineno, "a string "
+                          "must exist before the first `,'. You have "
+                          "given: `%s'", string);
+          *c='\0';
+          gal_list_str_add(&list, str, 1);
+          str=NULL;  /* Mark that the next character is the start */
+          break;
+
+        /* If the character isn't a coma, it is either in the middle of a
+           string at the start of it. If `str==NULL', then it is at the
+           start. */
+        default: if(str==NULL) str=c;
+        }
+
+      /* Increment C. */
+      ++c;
+    }
+
+
+  /* If the last element wasn't a comma, the last string hasn't been added
+     to the list yet. */
+  if(str) gal_list_str_add(&list, str, 1);
+
+
+  /* Allocate the output data structure and fill it up. */
+  if(list)
+    {
+      i=num=gal_list_str_number(list);
+      out=gal_data_alloc(NULL, GAL_TYPE_STRING, 1, &num, NULL, 0,
+                         minmapsize, NULL, NULL, NULL);
+      for(tstrll=list;tstrll!=NULL;tstrll=tstrll->next)
+        ((char **)(out->array))[--i]=tstrll->v;
+    }
+  else
+    {
+      /* It is not possible to allocate a dataset with a size of 0 along
+         any dimension (in C it's possible, but conceptually it isn't). So,
+         we'll allocate space for one element, then free it. */
+      i=1;
+      out=gal_data_alloc(NULL, GAL_TYPE_STRING, 1, &i, NULL, 0,
+                         minmapsize, NULL, NULL, NULL);
+      out->size=out->dsize[0]=0;
+      free(out->array);
+      out->array=NULL;
+    }
+
+
+  /* Clean up and return. Note that we don't want to free the space of
+     each string becuse it has been passed  */
+  gal_list_str_free(list, 0);
+  return out;
+}
+
+
+
+
+
+/* `arg' is the value given to an option. It contains multiple strings
+   separated by a comma (`,'). This function will parse `arg' and make a
+   `gal_data_t' that contains all the strings separately. The output
+   `gal_data_t' will be put in `option->value'. */
+void *
+gal_options_parse_csv_strings(struct argp_option *option, char *arg,
+                              char *filename, size_t lineno, void *junk)
+{
+  int i;
+  size_t nc;
+  char **strarr;
+  gal_data_t *values;
+  char *str, sstr[GAL_OPTIONS_STATIC_MEM_FOR_VALUES];
+
+  /* We want to print the stored values. */
+  if(lineno==-1)
+    {
+      /* Set the pointer to the values dataset. */
+      values = *(gal_data_t **)(option->value);
+
+      /* Write each string into the output string */
+      nc=0;
+      strarr=values->array;
+      for(i=0;i<values->size;++i)
+        {
+          if( nc > GAL_OPTIONS_STATIC_MEM_FOR_VALUES-100 )
+            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s so we "
+                  "can address the problem. The number of necessary "
+                  "characters in the statically allocated string has become "
+                  "too close to %d", __func__, PACKAGE_BUGREPORT,
+                  GAL_OPTIONS_STATIC_MEM_FOR_VALUES);
+          nc += sprintf(sstr+nc, "%s,", strarr[i]);
+        }
+      sstr[nc-1]='\0';
+
+      /* Copy the string into a dynamically allocated space, because it
+         will be freed later.*/
+      gal_checkset_allocate_copy(sstr, &str);
+      return str;
+    }
+
+  /* We want to read the user's string. */
+  else
+    {
+      /* If the option is already set, just return. */
+      if(option->set) return NULL;
+
+      /* Read the values. */
+      values=gal_options_parse_csv_strings_raw(arg, filename, lineno);
+
+      /* Put the values into the option. */
+      *(gal_data_t **)(option->value) = values;
+      return NULL;
+    }
+}
+
+
+
+
+
 /* Parse the given string into a series of size values (integers, stored as
    an array of size_t). The ouput array will be stored in the `value'
-   element of the option. The last element of the array is `-1' to allow
-   finding the number of elements within it later (similar to a string
-   which terminates with a '\0' element). */
+   element of the option. The last element of the array is
+   `GAL_BLANK_SIZE_T' to allow finding the number of elements within it
+   later (similar to a string which terminates with a '\0' element). */
 void *
 gal_options_parse_sizes_reverse(struct argp_option *option, char *arg,
                                 char *filename, size_t lineno, void *junk)
@@ -587,14 +732,14 @@ gal_options_parse_sizes_reverse(struct argp_option 
*option, char *arg,
       for(i=0;i<values->size;++i)
         {
           if(v[i]<0)
-            error_at_line(EXIT_FAILURE, 0, filename, lineno, "the given "
+            error_at_line(EXIT_FAILURE, 0, filename, lineno, "a given "
                           "value in `%s' (%g) is not 0 or positive. The "
                           "values to the `--%s' option must be positive",
                           arg, v[i], option->name);
 
 
           if(ceil(v[i]) != v[i])
-            error_at_line(EXIT_FAILURE, 0, filename, lineno, "the given "
+            error_at_line(EXIT_FAILURE, 0, filename, lineno, "a given "
                           "value in `%s' (%g) is not an integer. The "
                           "values to the `--%s' option must be integers",
                           arg, v[i], option->name);
@@ -605,7 +750,7 @@ gal_options_parse_sizes_reverse(struct argp_option *option, 
char *arg,
       num=values->size;
       array=gal_data_malloc_array(GAL_TYPE_SIZE_T, num+1, __func__, "array");
       for(i=0;i<num;++i) array[num-1-i]=v[i];
-      array[num] = (size_t)(-1);
+      array[num] = GAL_BLANK_SIZE_T;
 
       /* Put the array of size_t into the option, clean up and return.*/
       *(size_t **)(option->value) = array;
diff --git a/tests/mkprof/mosaic1.sh b/tests/mkprof/mosaic1.sh
index ba9dd03..8cdc6f3 100755
--- a/tests/mkprof/mosaic1.sh
+++ b/tests/mkprof/mosaic1.sh
@@ -50,5 +50,5 @@ if [ ! -f $cat      ]; then echo "$cat does not exist.";   
exit 77; fi
 
 # Actual test script
 # ==================
-$execname $cat --naxis1=100 --naxis2=100
+$execname $cat --naxis=100,100
 mv 0_mkprofcat1.fits psf.fits
diff --git a/tests/mkprof/mosaic2.sh b/tests/mkprof/mosaic2.sh
index 63171fc..8575bb7 100755
--- a/tests/mkprof/mosaic2.sh
+++ b/tests/mkprof/mosaic2.sh
@@ -55,4 +55,4 @@ if [ ! -f $cat      ]; then echo "$cat does not exist.";   
exit 77; fi
 
 # Actual test script
 # ==================
-$execname $cat --naxis1=100 --naxis2=100 --crpix1=-99 --individual
+$execname $cat --naxis=100,100 --crpix=-99,1 --individual
diff --git a/tests/mkprof/mosaic3.sh b/tests/mkprof/mosaic3.sh
index 7cf5322..c513f92 100755
--- a/tests/mkprof/mosaic3.sh
+++ b/tests/mkprof/mosaic3.sh
@@ -52,4 +52,4 @@ if [ ! -f $cat      ]; then echo "$cat does not exist.";   
exit 77; fi
 
 # Actual test script
 # ==================
-$execname $cat --naxis1=100 --naxis2=100 --crpix2=-99
+$execname $cat --naxis=100,100 --crpix=1,-99
diff --git a/tests/mkprof/mosaic4.sh b/tests/mkprof/mosaic4.sh
index c495fd7..16120e8 100755
--- a/tests/mkprof/mosaic4.sh
+++ b/tests/mkprof/mosaic4.sh
@@ -53,4 +53,4 @@ if [ ! -f $cat      ]; then echo "$cat does not exist.";   
exit 77; fi
 
 # Actual test script
 # ==================
-$execname $cat --naxis1=100 --naxis2=100 --crpix1=-99 --crpix2=-99
+$execname $cat --naxis=100,100 --crpix=-99,-99
diff --git a/tests/mkprof/radeccat.sh b/tests/mkprof/radeccat.sh
index 9bae1c4..fdcf564 100755
--- a/tests/mkprof/radeccat.sh
+++ b/tests/mkprof/radeccat.sh
@@ -48,4 +48,4 @@ if [ ! -f $cat      ]; then echo "$cat does not exist.";   
exit 77; fi
 
 # Actual test script
 # ==================
-$execname $cat --racol=RA --deccol=Dec --naxis1=100 --naxis2=100
+$execname $cat --ccol=RA --ccol=Dec --mode=wcs --naxis=100,100



reply via email to

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