gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master f25b55e 005/113: Merged with recent changes in


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master f25b55e 005/113: Merged with recent changes in master
Date: Fri, 16 Apr 2021 10:33:30 -0400 (EDT)

branch: master
commit f25b55ea927e49aedc8cbb6c90ad48d721d3f7e2
Merge: 17d6f65 2d7517d
Author: Mohammad Akhlaghi <akhlaghi@gnu.org>
Commit: Mohammad Akhlaghi <akhlaghi@gnu.org>

    Merged with recent changes in master
---
 NEWS                            |  22 ++
 THANKS                          |   1 +
 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 ++-
 bin/noisechisel/clumps.c        |  38 +++-
 doc/gnuastro.texi               | 166 +++++++++------
 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 +-
 21 files changed, 974 insertions(+), 521 deletions(-)

diff --git a/NEWS b/NEWS
index eec8394..926dc3b 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).
+
+  NoiseChisel segfault when no usable region for sky clumps (bug #51372).
 
 
 
diff --git a/THANKS b/THANKS
index 63651a2..bed7f05 100644
--- a/THANKS
+++ b/THANKS
@@ -22,6 +22,7 @@ support in Gnuastro. The list is ordered alphabetically.
     Rosa Calvi                           rcalvi@iac.es
     Antonio Diaz Diaz                    antonio@gnu.org
     Takashi Ichikawa                     ichikawa@astr.tohoku.ac.jp
+    Raúl Infante Sainz                   infantesainz@gmail.com
     Brandon Invergo                      brandon@gnu.org
     Lee Kelvin                           l.s.kelvin@ljmu.ac.uk
     Mohammad-Reza Khellat                moha.khe@gmail.com
diff --git a/bin/crop/main.h b/bin/crop/main.h
index 515c75c..a61e50e 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                  3
 
 
-/* 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/bin/noisechisel/clumps.c b/bin/noisechisel/clumps.c
index c16b9d0..459b212 100644
--- a/bin/noisechisel/clumps.c
+++ b/bin/noisechisel/clumps.c
@@ -107,6 +107,10 @@ clumps_oversegment(struct clumps_thread_params *cltprm)
   **********************************************/
 
 
+  /* If the size of the indexs is zero, then this function is pointless. */
+  if(indexs->size==0) { cltprm->numinitclumps=0; return; }
+
+
   /* Sort the given indexs based on their flux (`gal_qsort_index_arr' is
      defined as static in `gnuastro/qsort.h') */
   gal_qsort_index_arr=p->conv->array;
@@ -146,10 +150,10 @@ clumps_oversegment(struct clumps_thread_params *cltprm)
 
             /* A small sanity check. */
             if(Q!=NULL || cleanup!=NULL)
-              error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s so we 
"
-                    "can fix this problem. `Q' and `cleanup' should be NULL "
-                    "but while checking the equal flux regions they aren't",
-                    __func__, PACKAGE_BUGREPORT);
+              error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s so "
+                    "we can fix this problem. `Q' and `cleanup' should be "
+                    "NULL but while checking the equal flux regions they "
+                    "aren't", __func__, PACKAGE_BUGREPORT);
 
             /* Add this pixel to a queue. */
             gal_list_sizet_add(&Q, *a);
@@ -808,6 +812,10 @@ clumps_make_sn_table(struct clumps_thread_params *cltprm)
   size_t i, ind, counter=0, infodsize[2]={tablen, INFO_NCOLS};
 
 
+  /* If there were no initial clumps, then ignore this function. */
+  if(cltprm->numinitclumps==0) { cltprm->sn=NULL; return; }
+
+
   /* Allocate the arrays to keep the final S/N table (and possibly S/N
      index) for this object or tile. */
   cltprm->sn        = &cltprm->clprm->sn[ cltprm->id ];
@@ -920,8 +928,8 @@ clumps_correct_sky_labels_for_check(struct 
clumps_thread_params *cltprm,
 
   /* A small sanity check. */
   if(gal_tile_block(tile)!=p->clabel)
-    error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to address the "
-          "problem. `tile->block' must point to the `clabel' dataset",
+    error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to address "
+          "the problem. `tile->block' must point to the `clabel' dataset",
           __func__, PACKAGE_BUGREPORT);
 
 
@@ -1001,6 +1009,7 @@ clumps_find_make_sn_table(void *in_prm)
       cltprm.id = tind  = tprm->indexs[i];
       tile = &p->ltl.tiles[tind];
 
+
       /* Change the tile's pointers to the binary image (which has 1 for
          detected pixels and 0 for un-detected regions). */
       tarray=tile->array;
@@ -1008,6 +1017,7 @@ clumps_find_make_sn_table(void *in_prm)
       tile->array = gal_tile_block_relative_to_other(tile, p->binary);
       tile->block = p->binary;
 
+
       /* Get the number of usable elements in this tile (note that tiles
          can have blank pixels), so we can't simply use `tile->size'. */
       if(tile->flag & GAL_DATA_FLAG_HASBLANK)
@@ -1018,12 +1028,14 @@ clumps_find_make_sn_table(void *in_prm)
         }
       else num=tile->size;
 
+
       /* Find the number of detected pixels over this tile. Since this is
          the binary image, this is just the sum of all the pixels. */
       tmp=gal_statistics_sum(tile);
       numdet=*((double *)(tmp->array));
       gal_data_free(tmp);
 
+
       /* See if this tile should be used or not (has enough undetected
          pixels). Note that it might happen that some tiles are fully
          blank. In such cases, it is important to first check the number of
@@ -1043,6 +1055,7 @@ clumps_find_make_sn_table(void *in_prm)
           tile->array = gal_tile_block_relative_to_other(tile, p->clabel);
           tile->block = p->clabel;
 
+
           /* We need to set all the pixels on the edge of the tile to
              rivers and not include them in the list of indexs to set
              clumps. To do that, we need this tile's starting
@@ -1052,6 +1065,7 @@ clumps_find_make_sn_table(void *in_prm)
                                                          p->clabel->type),
                                        ndim, dsize, scoord);
 
+
           /* Add the index of every sky element to the array of
              indexs. Note that since we know the array is always of type
              `int32_t', we can call the `GAL_TILE_PO_OISET' macro to avoid
@@ -1103,30 +1117,37 @@ clumps_find_make_sn_table(void *in_prm)
                 }
             });
 
+
           /* Correct the number of indexs. */
           cltprm.indexs->size=cltprm.indexs->dsize[0]=c;
 
+
           /* Generate the clumps over this region. */
           clumps_oversegment(&cltprm);
 
+
           /* Set all river pixels to CLUMPS_INIT (to be distinguishable
              from the detected regions). */
           GAL_TILE_PO_OISET( int32_t, int, tile, NULL, 0, 1,
                              {if(*i==CLUMPS_RIVER) *i=CLUMPS_INIT;} );
 
+
           /* For a check, the step variable will be set. */
           if(clprm->step==1)
             { gal_data_free(cltprm.indexs); continue; }
 
+
           /* Make the clump S/N table. */
           clumps_make_sn_table(&cltprm);
 
+
           /* If the user wanted to check the steps, remove the clumps that
              weren't used from the `clabel' image (they have been already
              excluded from the table). */
           if(cltprm.snind)
             clumps_correct_sky_labels_for_check(&cltprm, tile);
 
+
           /* Clean up. */
           gal_data_free(cltprm.indexs);
         }
@@ -1255,10 +1276,11 @@ clumps_true_find_sn_thresh(struct noisechiselparams *p)
   else
     {
       clprm.step=0;
-      gal_threads_spin_off(clumps_find_make_sn_table, &clprm, p->ltl.tottiles,
-                           p->cp.numthreads);
+      gal_threads_spin_off(clumps_find_make_sn_table, &clprm,
+                           p->ltl.tottiles, p->cp.numthreads);
     }
 
+
   /* Destroy the mutex if it was initialized. */
   if( p->cp.numthreads>1 && (p->checksegmentation || p->checkclumpsn) )
     pthread_mutex_destroy(&clprm.labmutex);
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index faad1b4..487e911 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -1938,8 +1938,8 @@ $ astmkprof -P
 [[[ ... Truncated lines ... ]]]
 
 # Columns, by info (see `--searchin'), or number (starting from 1):
- xcol         2           # Center along first FITS axis (horizontal).
- ycol         3           # Center along second FITS axis (vertical).
+ ccol         2           # Center along first FITS axis (horizontal).
+ ccol         3           # Center along second FITS axis (vertical).
  fcol         4           # sersic (1), moffat (2), gaussian (3),
                           # point (4), flat (5), circumference (6).
  rcol         5           # Effective radius or FWHM in pixels.
@@ -2015,8 +2015,7 @@ necessary parameters and runs MakeProfiles with the 
following command:
 
 @example
 
-$ astmkprof --prepforconv --naxis1=500 --naxis2=500         \
-            --zeropoint=18.0 cat.txt
+$ astmkprof --prepforconv --naxis=500,500 --zeropoint=18.0 cat.txt
 MakeProfiles started on Sat Oct  6 16:26:56 953
   - 6 profiles read from cat.txt
   - Random number generator (RNG) type: mt19937
@@ -2182,8 +2181,7 @@ base=cat
 rm out.fits
 
 # Run MakeProfiles to create an oversampled FITS image.
-astmkprof --prepforconv --naxis1=500 --naxis2=500                \
-          --zeropoint=18.0 "$base".txt
+astmkprof --prepforconv --naxis=500,500 --zeropoint=18.0 "$base".txt
 
 # Convolve the created image with the kernel.
 astconvolve --kernel=0_"$base".fits "$base".fits
@@ -14716,11 +14714,11 @@ $ astmkprof --background=image.fits catalog.txt
 $ astmkprof --kernel=moffat,2.8,5 --oversample=1
 
 ## Make profiles in catalog, using RA and Dec in the given column:
-$ astmkprof --racol=RA_CENTER --ycol=DEC_CENTER catalog.txt
+$ astmkprof --ccol=RA_CENTER --ccol=DEC_CENTER --mode=wcs catalog.txt
 
 ## Make a 1500x1500 merged image (oversampled 500x500) image along
 ## with an individual image for all the profiles in catalog:
-$ astmkprof --individual --oversample 3 -x500 -y500 catalog.txt
+$ astmkprof --individual --oversample 3 --naxis=500,500 catalog.txt
 @end example
 
 @noindent
@@ -14870,22 +14868,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}.
 
-@item -x INT
-@itemx --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.
+@item -x INT,INT
+@itemx --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.
 
-@item -y INT
-@itemx --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
-@option{--naxis1}.
+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
@@ -14970,18 +14970,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'.
 
-@item -X INT
-@itemx --xshift=INT
-Shift all the profiles and enlarge the image along the first FITS axis, 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 -Y INT
-@itemx --yshift=INT
-Similar to @option{--xshift} for the second FITS axis.
+@item -X INT,INT
+@itemx --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
@@ -15048,7 +15044,7 @@ profile. However, when using flat profiles with the
 @code{0.0} value as the flat profile's pixel value.
 
 @item -C
-@item --clearcanvas
+@itemx --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
@@ -15079,6 +15075,19 @@ column number, where counting starts from zero.
 
 @table @option
 
+@item --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.
+
+@item --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
+@option{--ccol=RA} 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
@@ -15111,27 +15120,6 @@ value will be used for all pixels between the 
truncation radius
 @option{--circumwidth}).
 @end itemize
 
-@item --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.
-
-@item --ycol=STR/INT
-The center of the profiles along the second FITS axis (vertical when viewed
-in SAO ds9). Similar to @option{--xcol}.
-
-@item --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
-@option{--xcol} 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.
-
-@item --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.
@@ -15196,26 +15184,61 @@ 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
+@url{https://doi.org/10.1051/0004-6361/201015362, Pence et al [2010]} for a
+short introduction to WCS in the FITS standard@footnote{The 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
+@url{https://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
+@url{http://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:
+@command{$ astfits -p image.fits}.
+
+If the values given to all of these options does not correspond to the
+dimensionality of the output dataset, then no WCS information will be
+added.
 
 @table @option
 
-@item --crpix1=FLT
-The pixel coordinates of the WCS reference point on the first (horizontal)
-FITS axis (counting from 1).
+@item --crpix=FLT,FLT
+The pixel coordinates of the WCS reference point. Fractions are acceptable
+for the values of this option.
 
-@item --crpix2=FLT
-The pixel coordinates of the WCS reference point on the second (vertical)
-FITS axis (counting from 1).
+@item --crval=FLT,FLT
+The WCS coordinates of the Reference point. Fractions are acceptable for
+the values of this option.
 
-@item --crval1=FLT
-The Right Ascension (RA) of the reference point.
+@item --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.
+
+@item --pc=FLT,FLT,FLT,FLT
+The PC matrix of the WCS rotation, see the FITS standard (link above) to
+better understand the PC matrix.
 
-@item --crval2=FLT
-The Declination of the reference point.
+@item --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.
 
-@item --resolution=FLT
-The resolution of the non-oversampled image in units of arcseconds/pixel.
+@item --ctype=STR,STR
+The type of each WCS axis, for example @code{RA---TAN} and
+@code{DEC--TAN}. 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
 
@@ -17992,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}.
+
+@code{ndim} may be zero. In this case no allocation will occur,
+@code{data->array} and @code{data->dsize} will be set to @code{NULL} and
+@code{data->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 {gal_data_t *} 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 20b16f6..befbdfd 100644
--- a/lib/gnuastro-internal/options.h
+++ b/lib/gnuastro-internal/options.h
@@ -239,11 +239,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);
-
-
 
 
 /**********************************************************************/
@@ -269,6 +264,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 c90eb3c..3f0277b 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,13 +732,13 @@ 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);
@@ -604,7 +749,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]