gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 95d7fc5: Match: New --coord option for single


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 95d7fc5: Match: New --coord option for single coordinate matching
Date: Tue, 5 Mar 2019 21:18:08 -0500 (EST)

branch: master
commit 95d7fc596dcd4b6947e37412f78b59a2ac30b28a
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Match: New --coord option for single coordinate matching
    
    Until now, when trying to match a single point to another catalog, it was
    necessary to make a single-row table. With this option, its now possible to
    specify the points directly on the command-line and avoid having to make an
    extra file (which you probably need to delete afterwards).
---
 NEWS                               |   7 +
 bin/match/args.h                   |  14 ++
 bin/match/astmatch.conf            |   4 +-
 bin/match/main.h                   |   3 +-
 bin/match/match.c                  |  99 ++++++++--
 bin/match/ui.c                     | 366 +++++++++++++++++++++++++------------
 bin/match/ui.h                     |   3 +-
 doc/gnuastro.texi                  |  44 ++++-
 lib/gnuastro-internal/commonopts.h |   2 +-
 lib/gnuastro/type.h                |   3 +
 lib/options.c                      |  16 +-
 lib/type.c                         |  24 ++-
 tests/match/merged-cols.sh         |   4 +-
 tests/match/positions.sh           |   4 +-
 14 files changed, 440 insertions(+), 153 deletions(-)

diff --git a/NEWS b/NEWS
index 398d8fb..29a09bc 100644
--- a/NEWS
+++ b/NEWS
@@ -52,6 +52,12 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
      contain all the columns from the first input and the 5th column of the
      second input. This greatly simplifies the mergining of different table
      columns into one.
+   --coord: manually specify coordinates to match on the
+     command-line. Until now, if you only wanted to make check a specific
+     coordinate's matching with a catalog. It was necessary to make a
+     single-row catalog as a file and feed that into Match. With this
+     option, you can now specify the coordinates to match against another
+     catalog with the command-line.
 
   NoiseChisel:
    --interpmetric: Set the metric to use to identify the nearest neighbors
@@ -86,6 +92,7 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
     gal_dimension_dist_radial: Radial distance between two coordinates.
     gal_statistics_outlier_cumulative: Uses flatness of the cumulative
        distribution to find outliers.
+    gal_type_is_int: to see if we have an integer (any width, any sign).
 
 ** Removed features
 
diff --git a/bin/match/args.h b/bin/match/args.h
index 0509970..657cf73 100644
--- a/bin/match/args.h
+++ b/bin/match/args.h
@@ -129,6 +129,20 @@ struct argp_option program_options[] =
       gal_options_parse_csv_strings
     },
     {
+      "coord",
+      UI_KEY_COORD,
+      "FLT[,FLT]",
+      0,
+      "Manually input coordiantes.",
+      UI_GROUP_CATALOGMATCH,
+      &p->coord,
+      GAL_TYPE_STRING,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET,
+      gal_options_parse_csv_float64
+    },
+    {
       "aperture",
       UI_KEY_APERTURE,
       "FLT[,FLT[,FLT]]",
diff --git a/bin/match/astmatch.conf b/bin/match/astmatch.conf
index 6506993..85a90ec 100644
--- a/bin/match/astmatch.conf
+++ b/bin/match/astmatch.conf
@@ -20,6 +20,4 @@
 # Input
  hdu2            1
 
-# Catalog matching
- ccol1           2,3
- ccol2           2,3
\ No newline at end of file
+# Catalog matching
\ No newline at end of file
diff --git a/bin/match/main.h b/bin/match/main.h
index f9a5a85..1e776a6 100644
--- a/bin/match/main.h
+++ b/bin/match/main.h
@@ -53,8 +53,9 @@ struct matchparams
   char            *input1name;  /* First input filename.                */
   char            *input2name;  /* Second input filename.               */
   char                  *hdu2;  /* Second input's HDU.                  */
-  gal_data_t           *ccol1;  /* Array of firs input column names.    */
+  gal_data_t           *ccol1;  /* Array of first input column names.   */
   gal_data_t           *ccol2;  /* Array of second input column names.  */
+  gal_data_t           *coord;  /* Array of manual coordinate values.   */
   gal_data_t         *outcols;  /* Array of second input column names.  */
   gal_data_t        *aperture;  /* Acceptable matching aperture.        */
   uint8_t         logasoutput;  /* Don't rearrange inputs, out is log.  */
diff --git a/bin/match/match.c b/bin/match/match.c
index 94132a1..e32a74b 100644
--- a/bin/match/match.c
+++ b/bin/match/match.c
@@ -97,6 +97,57 @@ match_add_all_cols(char *filename, char *extname, 
gal_list_str_t *stdinlines,
 
 
 
+static gal_data_t *
+match_cat_from_coord(struct matchparams *p, gal_list_str_t *cols,
+                     size_t *numcolmatch)
+{
+  void *rptr;
+  gal_list_str_t *col;
+  uint8_t read, readtype;
+  size_t colcounter, counter;
+  gal_data_t *tmp, *ttmp, *out=NULL;
+
+  /* Go over the desired columns and only return the good ones. */
+  colcounter=0;
+  for(col=cols;col!=NULL;col=col->next)
+    {
+      /* In `ui_preparations_out_cols', we have done the necessary sanity
+         checks, so we can safely use the values. */
+      rptr=gal_type_string_to_number(col->v, &readtype);
+      if(readtype!=GAL_TYPE_UINT8)
+        error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
+              "the problem. The given string didn't have a `uint8' type",
+              __func__, PACKAGE_BUGREPORT);
+      read=*((uint8_t *)rptr);
+
+      /* Find the proper column in the second input's columns. Just note
+         that column counting starts from 1.*/
+      counter=1;
+      for(tmp=p->cols2;tmp!=NULL;tmp=tmp->next)
+        if(counter++ == read)
+          {
+            ttmp=gal_data_copy(tmp);
+            ttmp->next=NULL;
+            gal_list_data_add(&out, ttmp);
+            ++numcolmatch[colcounter];
+            break;
+          }
+
+      /* Increment the column counter. */
+      ++colcounter;
+    }
+
+  /* Reverse the list. */
+  gal_list_data_reverse(&out);
+
+  /* Return the output columns. */
+  return out;
+}
+
+
+
+
+
 /* Read the catalog in the given file and use the given permutation to keep
    the proper columns. */
 static gal_data_t *
@@ -143,18 +194,21 @@ match_catalog_read_write_all(struct matchparams *p, 
size_t *permutation,
       /* When the output contains columns from both inputs, we need to keep
          the number of columns matched against each column identifier. */
       *numcolmatch=gal_pointer_allocate(GAL_TYPE_SIZE_T,
-                                        gal_list_str_number(cols), 0,
+                                        gal_list_str_number(cols), 1,
                                         __func__, "numcolmatch");
     }
   else cols=incols;
 
 
-  /* Read the full table and free the `cols' array if it was allocated
-     here. */
-  cat=gal_table_read(filename, hdu, filename ? NULL : p->stdinlines, cols,
-                     p->cp.searchin, p->cp.ignorecase, p->cp.minmapsize,
-                     *numcolmatch);
-  origsize=cat->size;
+  /* Read the full table. NOTE that with `--coord', for the second input,
+     both `filename' and `p->stdinlines' will be NULL. */
+  if(filename || p->stdinlines)
+    cat=gal_table_read(filename, hdu, filename ? NULL : p->stdinlines, cols,
+                       p->cp.searchin, p->cp.ignorecase, p->cp.minmapsize,
+                       *numcolmatch);
+  else
+    cat=match_cat_from_coord(p, cols, *numcolmatch);
+  origsize = cat ? cat->size : 0;
 
 
   /* Go over each column and permute its contents. */
@@ -198,10 +252,11 @@ match_catalog_read_write_all(struct matchparams *p, 
size_t *permutation,
           }
       }
 
+
   /* Write the catalog to the output. */
   if(p->outcols)
     return cat;
-  else
+  else if(cat)
     {
       /* Write the catalog to a file. */
       gal_table_write(cat, NULL, p->cp.tableformat, outname, extname, 0);
@@ -227,8 +282,9 @@ match_catalog_read_write_all(struct matchparams *p, size_t 
*permutation,
 
       /* Clean up. */
       gal_list_data_free(cat);
-      return NULL;
     }
+
+  return NULL;
 }
 
 
@@ -380,7 +436,14 @@ match_catalog(struct matchparams *p)
 
   /* Print the number of matches if not in quiet mode. */
   if(!p->cp.quiet)
-    fprintf(stdout, "%zu\n", nummatched);
+    {
+      fprintf(stdout, "Number of maching rows in both catalogs: %zu\n",
+              nummatched);
+      if(p->out2name && strcmp(p->out1name, p->out2name))
+        fprintf(stdout, "Output:\n %s\n %s", p->out1name, p->out2name);
+      else
+        fprintf(stdout, "Output: %s\n", p->out1name);
+    }
 }
 
 
@@ -409,8 +472,16 @@ void
 match(struct matchparams *p)
 {
   /* Do the correct type of matching. */
-  if(p->mode==MATCH_MODE_CATALOG)
-    match_catalog(p);
+  switch(p->mode)
+    {
+    case MATCH_MODE_CATALOG: match_catalog(p); break;
+    case MATCH_MODE_WCS:
+      error(EXIT_FAILURE, 0, "matching by WCS is not yet supported");
+    default:
+      error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s to fix "
+            "the problem: %d is not a recognized mode",
+            __func__, PACKAGE_BUGREPORT, p->mode);
+    }
 
   /* Write Match's configuration as keywords into the first extension of
      the output. */
@@ -420,7 +491,9 @@ match(struct matchparams *p)
                                               ? p->input1name
                                               : "Standard input" ),
                                   &p->cp.okeys, 1);
-      gal_fits_key_write_filename("input2", p->input2name, &p->cp.okeys, 1);
+      gal_fits_key_write_filename("input2",
+                                  p->input2name?p->input2name:"--coord",
+                                  &p->cp.okeys, 1);
       gal_fits_key_write_config(&p->cp.okeys, "Match configuration",
                                 "MATCH-CONFIG", p->out1name, "0");
     }
diff --git a/bin/match/ui.c b/bin/match/ui.c
index 6423772..d569e87 100644
--- a/bin/match/ui.c
+++ b/bin/match/ui.c
@@ -224,24 +224,45 @@ ui_read_check_only_options(struct matchparams *p)
 
 
 
-
+/* Two necessary catalogs: First:  Standard input, or a file.
+                           Second: `--coord',      or a file.
+ */
 static void
 ui_check_options_and_arguments(struct matchparams *p)
 {
-  /* The first input might come from the standard input, in that case, the
-     second input's name is stored in `input1name' and `input2name' will be
-     left to NULL. So we'll first correct for this. */
-  if(p->input1name)
+  /* When `--coord' is given, there should be no second catalog
+     (argument). */
+  if(p->coord)
+    {
+      /* Make sure no second argument is given. */
+      if(p->input2name)
+        error(EXIT_FAILURE, 0, "only one argument can be given with the "
+              "`--coord' option");
+
+      /* No need for `p->input2name' or `p->ccol2'. */
+      gal_data_free(p->ccol2);
+      p->ccol2=NULL;
+    }
+
+  /* `--coord' is not given. */
+  else
     {
+      /* Without `coord' atleast one input is necessary. */
+      if(p->input1name==NULL)
+        error(EXIT_FAILURE, 0, "no inputs!\n\n"
+              "Two inputs are necessary. The first can be a file, or from "
+              "the standard input (e.g., a pipe). The second can be a "
+              "file, or its coordinates can be directly specified on the "
+              "command-line with `--coord'");
+
+      /* If the first input should be read from the standard input, the
+         contents of `input1name' actually belong to `input2name'. */
       if(p->input2name==NULL)
         {
           p->input2name=p->input1name;
           p->input1name=NULL;
         }
     }
-  else
-    error(EXIT_FAILURE, 0, "no inputs! two inputs are necessary. The first "
-          "can be from the standard input (e.g., a pipe)");
 
 
   /* If the first input is a FITS file, make sure its HDU is also given. */
@@ -253,20 +274,13 @@ ui_check_options_and_arguments(struct matchparams *p)
           "`--hdu' (`-h') option and give it the HDU number (starting "
           "from zero), extension name, or anything acceptable by "
           "CFITSIO");
-
-  /* If the second input is a FITS file, make sure its HDU is also
-     given. */
-  if(p->input2name)
-    {
-      if( gal_fits_name_is_fits(p->input2name) && p->hdu2==NULL )
-        error(EXIT_FAILURE, 0, "no HDU for second input. Please use the "
-              "`--hdu2' (`-H') option and give it the HDU number (starting "
-              "from zero), extension name, or anything acceptable by "
-              "CFITSIO");
-    }
-  else
-    error(EXIT_FAILURE, 0, "second input file not specified: two inputs are "
-          "necessary");
+  if( p->input2name
+      && gal_fits_name_is_fits(p->input2name)
+      && p->hdu2==NULL )
+    error(EXIT_FAILURE, 0, "no HDU for second input. Please use "
+          "the `--hdu2' (`-H') option and give it the HDU number "
+          "(starting from zero), extension name, or anything "
+          "acceptable by CFITSIO");
 }
 
 
@@ -294,41 +308,67 @@ ui_check_options_and_arguments(struct matchparams *p)
 static void
 ui_set_mode(struct matchparams *p)
 {
-  /* Check if we are in image or catalog mode. We will base the mode on the
-     first input, then check with the second. */
+  int tin1, tin2;
+  char *t1=NULL, *t2=NULL;
+
+  /* We will base the mode on the first input, then check with the
+     second. Note that when the first is from standard input (it is
+     `NULL'), then we go into catalog mode because currently we assume
+     standard input is only for plain text and WCS matching is not defined
+     on plain text. */
   if( p->input1name && gal_fits_name_is_fits(p->input1name) )
-    p->mode = ( (gal_fits_hdu_format(p->input1name, p->cp.hdu) == IMAGE_HDU)
-                ? MATCH_MODE_WCS
-                : MATCH_MODE_CATALOG );
+    {
+      tin1=gal_fits_hdu_format(p->input1name, p->cp.hdu);
+      p->mode = (tin1 == IMAGE_HDU) ? MATCH_MODE_WCS : MATCH_MODE_CATALOG;
+    }
   else
     p->mode=MATCH_MODE_CATALOG;
 
-  /* Now that the mode is set, check the second input's type. */
-  if( gal_fits_name_is_fits(p->input2name) )
+
+  /* Necessary sanity checks. */
+  if(p->mode==MATCH_MODE_CATALOG && p->cp.searchin==0)
+    error(EXIT_FAILURE, 0, "no `--searchin' option specified. Please run "
+          "the following command for more information:\n\n"
+          "    $ info gnuastro \"selecting table columns\"\n");
+
+
+  /* Now that the mode is set, do some sanity checks on the second
+     catalog. Recall that when `--coord' is given, there is no second input
+     file.*/
+  if(p->input2name)
     {
-      if(gal_fits_hdu_format(p->input2name, p->hdu2) == IMAGE_HDU)
+      if(gal_fits_name_is_fits(p->input2name))
         {
-          if( p->mode==MATCH_MODE_CATALOG)
-            error(EXIT_FAILURE, 0, "%s is a catalog, while %s is an image. "
-                  "Both inputs have to be images or catalogs",
-                  gal_checkset_dataset_name(p->input1name, p->cp.hdu),
-                  gal_checkset_dataset_name(p->input2name, p->hdu2) );
+          tin2=gal_fits_hdu_format(p->input2name, p->hdu2);
+          if(tin1==IMAGE_HDU && tin2!=IMAGE_HDU)
+            {
+              t1 = (tin1==IMAGE_HDU) ? "image" : "catalog";
+              t2 = (tin2==IMAGE_HDU) ? "image" : "catalog";
+            }
+          if(t1)
+            error(EXIT_FAILURE, 0, "%s is a %s, while %s is an "
+                  "%s. Both inputs have to be images or catalogs",
+                  gal_checkset_dataset_name(p->input1name, p->cp.hdu), t1,
+                  gal_checkset_dataset_name(p->input2name, p->hdu2), t2 );
         }
       else
         {
-          if( p->mode==MATCH_MODE_WCS)
-            error(EXIT_FAILURE, 0, "%s is an image, while %s is a catalog. "
+          if(p->mode==MATCH_MODE_WCS)
+            error(EXIT_FAILURE, 0, "%s is an image, while %s is a catalog! "
                   "Both inputs have to be images or catalogs",
                   gal_checkset_dataset_name(p->input1name, p->cp.hdu),
-                  gal_checkset_dataset_name(p->input2name, p->hdu2));
+                  gal_checkset_dataset_name(p->input2name, p->hdu2) );
         }
     }
   else
-    if(p->mode==MATCH_MODE_WCS)
-      error(EXIT_FAILURE, 0, "%s is an image, while %s is a catalog! Both "
-            "inputs have to be images or catalogs",
-            gal_checkset_dataset_name(p->input1name, p->cp.hdu),
-            gal_checkset_dataset_name(p->input2name, p->hdu2));
+    {
+      /* When there is no second-input file name (`--coord' is given), we
+         cannot be in WCS mode (requiring a FITS file). */
+      if(p->mode==MATCH_MODE_WCS)
+        error(EXIT_FAILURE, 0, "%s is an image, while `--coord' is only "
+              "meaningful for catalogs",
+              gal_checkset_dataset_name(p->input1name, p->cp.hdu));
+    }
 }
 
 
@@ -404,6 +444,100 @@ ui_read_columns_aperture_2d(struct matchparams *p)
 
 
 
+static size_t
+ui_set_columns_sanity_check_read_aperture(struct matchparams *p)
+{
+  size_t ccol1n, ccol2n;
+
+  /* Make sure the columns to read are given. */
+  if(p->coord)
+    {
+      if(p->ccol1==NULL)
+        error(EXIT_FAILURE, 0, "no value given to `--ccol1' (necessary with "
+              "`--coord')");
+    }
+  else
+    {
+      if(p->ccol1==NULL || p->ccol2==NULL)
+        error(EXIT_FAILURE, 0, "both `--ccol1' and `--ccol2' must be given. "
+              "They specify the columns containing the coordinates to match");
+    }
+
+  /* Make sure the same number of columns is given to both. */
+  ccol1n = p->ccol1->size;
+  ccol2n = p->coord ? p->coord->size : p->ccol2->size;
+  if(ccol1n!=ccol2n)
+    error(EXIT_FAILURE, 0, "number of coordinates given to `--ccol1' "
+          "(%zu) and `--%s' (%zu) must be equal.\n\n"
+          "If you didn't call these options, run with `--checkconfig' to "
+          "see which configuration file is responsible. You can always "
+          "override the configuration file values by calling the option "
+          "manually on the command-line",
+          ccol1n, p->coord ? "coord" : "ccol2", ccol2n);
+
+  /* Read/check the aperture values. */
+  if(p->aperture)
+    switch(ccol1n)
+      {
+      case 1:
+        if(p->aperture->size>1)
+          error(EXIT_FAILURE, 0, "%zu values given to `--aperture'. In a 1D "
+                "match, this option can only take one value",
+                p->aperture->size);
+        break;
+
+      case 2:
+        ui_read_columns_aperture_2d(p);
+        break;
+
+      default:
+        error(EXIT_FAILURE, 0, "%zu dimensional matches are not currently "
+              "supported (maximum is 2 dimensions). The number of "
+              "dimensions is deduced from the number of values given to "
+              "`--ccol1' (or `--coord') and `--ccol2'", ccol1n);
+      }
+  else
+    error(EXIT_FAILURE, 0, "no matching aperture specified. Please use "
+          "the `--aperture' option to define the acceptable aperture for "
+          "matching the coordinates (in the same units as each "
+          "dimension). Please run the following command for more "
+          "information.\n\n    $ info %s\n", PROGRAM_EXEC);
+
+  /* Return the number of dimensions. */
+  return ccol1n;
+}
+
+
+
+
+
+/* Save the manually given coordinates (with `--coord') in column format (a
+   list of datasets). */
+static gal_data_t *
+ui_set_columns_from_coord(struct matchparams *p)
+{
+  size_t i, one=1;
+  gal_data_t *out=NULL;
+  double *coord=p->coord->array;
+
+  /* Write each given value as a one-row table column (single element
+     datasets that are linked) */
+  for(i=0;i<p->coord->size;++i)
+    {
+      gal_list_data_add_alloc(&out, NULL, GAL_TYPE_FLOAT64, 1, &one, NULL,
+                              0, -1, NULL, NULL, NULL);
+      *((double *)(out->array))=coord[i];
+    }
+  gal_list_data_reverse(&out);
+
+  /* Return the list. */
+  return out;
+}
+
+
+
+
+
 /* We want to keep the columns as double type. So what-ever their original
    type is, convert it. */
 static gal_data_t *
@@ -469,72 +603,32 @@ ui_read_columns_to_double(struct matchparams *p, char 
*filename, char *hdu,
 static void
 ui_read_columns(struct matchparams *p)
 {
-  size_t i;
-  size_t ccol1n=p->ccol1->size;
-  size_t ccol2n=p->ccol2->size;
+  size_t i, ndim;
+  char **strarr1, **strarr2;
   gal_list_str_t *cols1=NULL, *cols2=NULL;
-  char **strarr1=p->ccol1->array, **strarr2=p->ccol2->array;
-
-  /* Make sure the same number of columns is given to both. */
-  if(ccol1n!=ccol2n)
-    error(EXIT_FAILURE, 0, "the number of values given to `--ccol1' and "
-          "`--ccol2' (%zu and %zu) are not equal", ccol1n, ccol2n);
-
-
-  /* Read/check the aperture values. */
-  if(p->aperture)
-    switch(ccol1n)
-      {
-      case 1:
-        if(p->aperture->size>1)
-          error(EXIT_FAILURE, 0, "%zu values given to `--aperture'. In a 1D "
-                "match, this option can only take one value",
-                p->aperture->size);
-        break;
-
-      case 2:
-        ui_read_columns_aperture_2d(p);
-        break;
-
-      default:
-
-        error(EXIT_FAILURE, 0, "%zu dimensional matches are not currently "
-              "supported (maximum is 2 dimensions). The number of "
-              "dimensions is deduced from the number of values given to "
-              "`--ccol1' and `--ccol2'", ccol1n);
-      }
-  else
-    error(EXIT_FAILURE, 0, "no matching aperture specified. Please use "
-          "the `--aperture' option to define the acceptable aperture for "
-          "matching the coordinates (in the same units as each "
-          "dimension). Please run the following command for more "
-          "information.\n\n    $ info %s\n", PROGRAM_EXEC);
 
+  /* Basic sanity checks and reading of aperture values. */
+  ndim=ui_set_columns_sanity_check_read_aperture(p);
 
   /* Convert the array of strings to a list of strings for the column
      names. */
-  for(i=0;i<ccol1n;++i)
+  strarr1=p->ccol1->array;
+  strarr2=p->coord?NULL:p->ccol2->array;
+  for(i=0;i<ndim;++i)
     {
       gal_list_str_add(&cols1, strarr1[i], 1);
-      gal_list_str_add(&cols2, strarr2[i], 1);
+      if(strarr2) gal_list_str_add(&cols2, strarr2[i], 1);
     }
   gal_list_str_reverse(&cols1);
-  gal_list_str_reverse(&cols2);
-
+  if(cols2) gal_list_str_reverse(&cols2);
 
-  /* Read the columns. */
-  if(p->cp.searchin)
-    {
-      /* Read the first dataset. */
-      p->cols1=ui_read_columns_to_double(p, p->input1name, p->cp.hdu,
-                                         cols1, ccol1n);
-      p->cols2=ui_read_columns_to_double(p, p->input2name, p->hdu2,
-                                         cols2, ccol2n);
-    }
-  else
-    error(EXIT_FAILURE, 0, "no `--searchin' option specified. Please run "
-          "the following command for more information:\n\n"
-          "    $ info gnuastro \"selecting table columns\"\n");
+  /* Read-in the columns. */
+  p->cols1=ui_read_columns_to_double(p, p->input1name, p->cp.hdu,
+                                     cols1, ndim);
+  p->cols2=( p->coord
+             ? ui_set_columns_from_coord(p)
+             : ui_read_columns_to_double(p, p->input2name, p->hdu2,
+                                         cols2, ndim) );
 
   /* Free the extra spaces. */
   gal_list_str_free(cols1, 1);
@@ -548,27 +642,65 @@ ui_read_columns(struct matchparams *p)
 static void
 ui_preparations_out_cols(struct matchparams *p)
 {
-  size_t i;
-  char **strarr=p->outcols->array;
+  void *rptr;
+  int goodvalue;
+  gal_data_t *read;
+  uint8_t readtype;
+  char *col, **strarr=p->outcols->array;
+  size_t i, one=1, ndim=p->coord?p->coord->size:0;
 
   /* Go over all the values and put the respective column identifier in the
      proper list. */
   for(i=0;i<p->outcols->size;++i)
-    switch(strarr[i][0])
-      {
-      case 'a': gal_list_str_add(&p->acols, strarr[i]+1, 0); break;
-      case 'b': gal_list_str_add(&p->bcols, strarr[i]+1, 0); break;
-      default:
-        error(EXIT_FAILURE, 0, "`%s' is not a valid value for `--outcols'. "
-              "The first character of each value to this option must be "
-              "either `a' or `b'. The former specifies a column from the "
-              "first input and the latter a column from the second. The "
-              "characters after them can be any column identifier (number, "
-              "name, or regular expression). For more on column selection, "
-              "please run this command:\n\n"
-              "    $ info gnuastro \"Selecting table columns\"\n",
-              strarr[i]);
-      }
+    {
+      col=strarr[i];
+      switch(col[0])
+        {
+        case 'a': gal_list_str_add(&p->acols, col+1, 0); break;
+        case 'b':
+          /* With `--coord', only numbers that are smaller than the number
+             of the dimensions are acceptable. */
+          if(p->coord)
+            {
+              goodvalue=0;
+              rptr=gal_type_string_to_number(col+1, &readtype);
+              if(rptr)
+                {
+                  read=gal_data_alloc(rptr, readtype, 1, &one, NULL, 0, -1,
+                                      NULL, NULL, NULL);
+                  if(gal_type_is_int(readtype))
+                    {
+                      read=gal_data_copy_to_new_type_free(read,GAL_TYPE_LONG);
+                      if( *((long *)(read->array)) <= ndim )
+                        goodvalue=1;
+                    }
+                  gal_data_free(read);
+                }
+              if(goodvalue==0)
+                error(EXIT_FAILURE, 0, "bad value to second catalog "
+                      "column (%s) of `--outcols'.\n\n"
+                      "With the `--coord' option, the second catalog is "
+                      "assumed to have a single row and the given number "
+                      "of columns. Therefore when using `--outcols', only "
+                      "integers that are less than the number of "
+                      "dimensions (%zu in this case) are acceptable", col+1,
+                      ndim);
+            }
+          gal_list_str_add(&p->bcols, col+1, 0);
+          break;
+        default:
+          error(EXIT_FAILURE, 0, "`%s' is not a valid value for "
+                "`--outcols'.\n\n"
+                "The first character of each value to this option must be "
+                "either `a' or `b'. The former specifies a column from the "
+                "first input and the latter a column from the second. The "
+                "characters after them can be any column identifier (number, "
+                "name, or regular expression). For more on column selection, "
+                "please run this command:\n\n"
+                "    $ info gnuastro \"Selecting table columns\"\n",
+                col);
+        }
+    }
 
   /* Revere the lists so they correspond to the input order. */
   gal_list_str_reverse(&p->acols);
@@ -611,7 +743,7 @@ ui_preparations_out_name(struct matchparams *p)
     }
   else
     {
-      if(p->outcols)
+      if(p->outcols || p->coord)
         {
           if(p->cp.output)
             gal_checkset_allocate_copy(p->cp.output, &p->out1name);
diff --git a/bin/match/ui.h b/bin/match/ui.h
index e949fb4..6d66082 100644
--- a/bin/match/ui.h
+++ b/bin/match/ui.h
@@ -40,7 +40,7 @@ enum program_args_groups
 
 /* Available letters for short options:
 
-   b d e f g i j k m n p r s t u v w x y z
+   b e f g i j k m n p r s t u v w x y z
    A B E G J L O Q R W X Y
 */
 enum option_keys_enum
@@ -51,6 +51,7 @@ enum option_keys_enum
   UI_KEY_LOGASOUTPUT     = 'l',
   UI_KEY_CCOL1           = 'c',
   UI_KEY_CCOL2           = 'C',
+  UI_KEY_COORD           = 'd',
 
   /* Only with long version (start with a value 1000, the rest will be set
      automatically). */
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index f9d36b3..6013bcc 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -19752,10 +19752,14 @@ $ astmatch --ccol1=RA,DEC --ccol2=RA_D,DEC_D 
--aperture=0.5/3600  \
            in1.fits in2.fits
 @end example
 
-Two inputs are necessary for Match to start processing. The inputs can be
-plain text tables or FITS tables, see @ref{Tables}. If only one argument is
-provided, Match will assume look for the first input in Standard input (see
address@hidden input}).
+Match will find the rows that are nearest to each other in two catalogs
+(given some coordinate columns). Therefore two catalogs are necessary for
+input. However, they don't necessarily have to be files: 1) the first
+catalog can also come from the standard input (for example a pipe, see
address@hidden input}); 2) when only one point is needed, you can use the
address@hidden option to avoid creating a file for the second
+catalog. When the inputs are files, they can be plain text tables or FITS
+tables, for more see @ref{Tables}.
 
 Match follows the same basic behavior of all Gnuastro programs as fully
 described in @ref{Common program behavior}. If the first input is a FITS
@@ -19848,6 +19852,15 @@ re-arrange the necessary columns and it will write a 
single output
 table. Combined with regular expressions in large tables, this can be a
 very powerful and convenient way to merge various tables into one.
 
+When @option{--coord} is given, no second catalog will be read. The second
+catalog will be created internally based on the values given to
address@hidden So column names aren't defined and you can only request
+integer column numbers that are less than the number of coordinates given
+to @option{--coord}. For example if you want to find the row matching RA of
+1.2345 and Dec of 6.7890, then you should use
address@hidden,6.7890}. But when using @option{--outcols}, you
+can't give @code{bRA}, or @code{b25}.
+
 @item -l
 @itemx --logasoutput
 The output file will have the contents of the log file: indexes in the two
@@ -19877,6 +19890,25 @@ columns}. See the one-line examples above for some 
usages of this option.
 The coordinate columns of the second input. See the example in
 @option{--ccol1} for more.
 
address@hidden -d FLT[,FLT]
address@hidden --coord=FLT[,FLT]
+Manually specify the coordinates to match against the given catalog. With
+this option, Match will not look for a second input file/table and will
+directly use the coordinates given to this option.
+
+When this option is called, the output changes in the following ways: 1)
+when @option{--outcols} is specified, for the second input, it can only
+accept integer numbers that are less than the number of values given to
+this option, see description of that option for more. 2) By default (when
address@hidden isn't used), only the matching row of the first table
+will be output (a single file), not two separate files (one for each
+table).
+
+This option is good when you have a (large) catalog and only want to match
+a single coordinate to it (for example to find the nearest catalog entry to
+your desired point). With this option, you can write the coordinates on the
+command-line and thus avoid the need to make a single-row file.
+
 @item -a FLT[,FLT[,FLT]]
 @itemx --aperture=FLT[,FLT[,FLT]]
 Parameters of the aperture for matching. The values given to this option
@@ -23595,6 +23627,10 @@ Note: Do not use the maximum value for a blank value 
of a general
 @ref{Library blank values} for the definition and usage of blank values.
 @end deftypefun
 
address@hidden int gal_type_is_int (uint8_t @code{type})
+Return 1 if the type is an integer (any width and any sign).
address@hidden deftypefun
+
 @deftypefun int gal_type_is_list (uint8_t @code{type})
 Return 1 if the type is a linked list and zero otherwise.
 @end deftypefun
diff --git a/lib/gnuastro-internal/commonopts.h 
b/lib/gnuastro-internal/commonopts.h
index 96046c2..cadd541 100644
--- a/lib/gnuastro-internal/commonopts.h
+++ b/lib/gnuastro-internal/commonopts.h
@@ -266,7 +266,7 @@ struct argp_option gal_commonopts_options[] =
       GAL_OPTIONS_KEY_TABLEFORMAT,
       "STR",
       0,
-      "Table format: `fits-ascii', `fits-binary'.",
+      "Table fmt: `fits-ascii', `fits-binary', `txt'.",
       GAL_OPTIONS_GROUP_OUTPUT,
       &cp->tableformat,
       GAL_TYPE_STRING,
diff --git a/lib/gnuastro/type.h b/lib/gnuastro/type.h
index a57214e..195cfce 100644
--- a/lib/gnuastro/type.h
+++ b/lib/gnuastro/type.h
@@ -138,6 +138,9 @@ void
 gal_type_max(uint8_t type, void *in);
 
 int
+gal_type_is_int(uint8_t type);
+
+int
 gal_type_is_list(uint8_t type);
 
 int
diff --git a/lib/options.c b/lib/options.c
index 2e176ed..5e1d38a 100644
--- a/lib/options.c
+++ b/lib/options.c
@@ -528,10 +528,10 @@ gal_options_read_interpmetric(struct argp_option *option, 
char *arg,
           gal_checkset_allocate_copy("manhattan", &str);
           break;
         default:
-          error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix 
the "
-                "problem. The code %u is not recognized as a nearest-neighbor "
-                "interpolation metric", __func__, PACKAGE_BUGREPORT,
-                *(uint8_t *)(option->value));
+          error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
+                "fix the problem. The code %u is not recognized as a "
+                "nearest-neighbor interpolation metric", __func__,
+                PACKAGE_BUGREPORT, *(uint8_t *)(option->value));
         }
       return str;
     }
@@ -546,10 +546,10 @@ gal_options_read_interpmetric(struct argp_option *option, 
char *arg,
       else if ( !strcmp(arg, "manhattan") )
         *(uint8_t *)(option->value) = GAL_INTERPOLATE_CLOSE_METRIC_MANHATTAN;
       else
-        error_at_line(EXIT_FAILURE, 0, filename, lineno, "`%s' (value to `%s' "
-                      "option) isn't valid. Currently only `radial' and "
-                      "`manhattan' metrics are recognized for nearest neighbor 
"
-                      "interpolation", arg, option->name);
+        error_at_line(EXIT_FAILURE, 0, filename, lineno, "`%s' (value to "
+                      "`%s' option) isn't valid. Currently only `radial' "
+                      "and `manhattan' metrics are recognized for nearest "
+                      "neighbor interpolation", arg, option->name);
 
       /* For no un-used variable warning. This function doesn't need the
          pointer. */
diff --git a/lib/type.c b/lib/type.c
index 560a305..af21dec 100644
--- a/lib/type.c
+++ b/lib/type.c
@@ -280,7 +280,29 @@ gal_type_max(uint8_t type, void *in)
     case GAL_TYPE_FLOAT32:      *(float *)    in = FLT_MAX;      break;
     case GAL_TYPE_FLOAT64:      *(double *)   in = DBL_MAX;      break;
     default:
-      error(EXIT_FAILURE, 0, "%s: type code %d not recognized", __func__, 
type);
+      error(EXIT_FAILURE, 0, "%s: type code %d not recognized", __func__,
+            type);
+    }
+}
+
+
+
+
+
+int
+gal_type_is_int(uint8_t type)
+{
+  switch(type)
+    {
+    case GAL_TYPE_UINT8:  return 1;
+    case GAL_TYPE_INT8:   return 1;
+    case GAL_TYPE_UINT16: return 1;
+    case GAL_TYPE_INT16:  return 1;
+    case GAL_TYPE_UINT32: return 1;
+    case GAL_TYPE_INT32:  return 1;
+    case GAL_TYPE_UINT64: return 1;
+    case GAL_TYPE_INT64:  return 1;
+    default:              return 0;
     }
 }
 
diff --git a/tests/match/merged-cols.sh b/tests/match/merged-cols.sh
index 3e4ac2a..9a21aa3 100755
--- a/tests/match/merged-cols.sh
+++ b/tests/match/merged-cols.sh
@@ -53,6 +53,6 @@ if [ ! -f $execname ]; then echo "$execname not created."; 
exit 77; fi
 # `check_with_program' can be something like `Valgrind' or an empty
 # string. Such programs will execute the command if present and help in
 # debugging when the developer doesn't have access to the user's system.
-$check_with_program $execname $cat1 $cat2 --aperture=0.5             \
-                              -omatch-merged-cols.txt                \
+$check_with_program $execname $cat1 $cat2 --aperture=0.5 --ccol1=2,3   \
+                               --ccol2=2,3 -omatch-merged-cols.txt     \
                               --outcols=a1,aEFGH,bACCU1,aIJKL,bACCU2
diff --git a/tests/match/positions.sh b/tests/match/positions.sh
index 2622750..e9b51c9 100755
--- a/tests/match/positions.sh
+++ b/tests/match/positions.sh
@@ -53,5 +53,5 @@ if [ ! -f $execname ]; then echo "$execname not created."; 
exit 77; fi
 # `check_with_program' can be something like `Valgrind' or an empty
 # string. Such programs will execute the command if present and help in
 # debugging when the developer doesn't have access to the user's system.
-$check_with_program $execname $cat1 $cat2 --aperture=0.5 --log    \
-                              --output=match-positions.fits
+$check_with_program $execname $cat1 $cat2 --aperture=0.5 --log --ccol1=2,3 \
+                              --ccol2=2,3 --output=match-positions.fits



reply via email to

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