gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 4154cba 2/2: Table: four new column arithmetic


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 4154cba 2/2: Table: four new column arithmetic operators to convert RA and Dec
Date: Wed, 8 Apr 2020 22:31:54 -0400 (EDT)

branch: master
commit 4154cba9a578c9df36ced4da28bd0ba178e8a32e
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Table: four new column arithmetic operators to convert RA and Dec
    
    In the previous commit, Kartik introduced two the four new operators and
    the necessary library functions. However, the names weren't too descriptive
    and have now been changed to `ra-to-degree', `dec-to-degree',
    `degree-to-ra' and `degree-to-dec'. Many stylistic corrections were also
    made to the original code to make it fit in better with the whole of
    Gnuastro and the necessary documentation was added.
    
    In the process, I also noticed that it is much better to specify column in
    column arithmetic with a `$' sign (like AWK), not the old `c' character.
---
 NEWS                      |  14 ++-
 bin/table/arithmetic.c    |   4 +-
 bin/table/table.c         |   2 +-
 doc/gnuastro.texi         | 133 ++++++++++++++++++---
 lib/arithmetic.c          |  64 +++++-----
 lib/gnuastro/arithmetic.h |   8 +-
 lib/gnuastro/units.h      |  19 ++-
 lib/units.c               | 290 +++++++++++++++++++++++++---------------------
 8 files changed, 333 insertions(+), 201 deletions(-)

diff --git a/NEWS b/NEWS
index cd07f34..70d50c7 100644
--- a/NEWS
+++ b/NEWS
@@ -48,7 +48,11 @@ See the end of the file for license conditions.
    --notequal: Can now work on columns with string type also.
    --catcolumn: Concatenate tables by column (keeping number of rows fixed).
    --catcolhdu: Specify the HDU/extension of the FITS files of --catcolumn.
-   - New `quantile' operator in column arithmetic.
+   - New operators in column arithmetic:
+     - `ra-to-degree': Convert Right Ascension (HH:MM:SS) to degrees.
+     - `dec-to-degree': Convert Declination (DD:MM:SS) to degrees.
+     - `degree-to-ra': Convert degrees to Right Ascension (HH:MM:SS).
+     - `degree-to-dec': Convert degrees to Declination (HH:MM:SS).
 
   Library:
    - GAL_SPECLINES_INVALID_MAX: Total number of spectral lines, plus 1.
@@ -94,6 +98,14 @@ See the end of the file for license conditions.
      value of zero. As a result, the Sky and Sky standard deviation
      extensions will be measured over all the tiles.
 
+  Table:
+   - In Column arithmetic, when columns must be specified by their number,
+     that number should be distinguished with a `$' before it (for example
+     `$1' means the first column). Until now, this character was `c', but
+     the new identifying character is very similar to AWK, allowing easier
+     adoption and is also more clear. It is just important to put the total
+     `arith' string within single quotes, not double quotes.
+
   Library:
    - gal_polygon_is_inside_convex: new name for `gal_polygon_pin'.
 
diff --git a/bin/table/arithmetic.c b/bin/table/arithmetic.c
index 50f2620..379dc5b 100644
--- a/bin/table/arithmetic.c
+++ b/bin/table/arithmetic.c
@@ -212,8 +212,8 @@ arithmetic_init(struct tableparams *p, struct 
arithmetic_token **arith,
           /* Token is a column operand (column number or name). */
           else
             {
-              str = ( (token[0]=='c' && isdigit(token[1]))
-                      ? &token[1]   /* Column number (starting with `c'). */
+              str = ( (token[0]=='$' && isdigit(token[1]))
+                      ? &token[1]   /* Column number (starting with `$'). */
                       : token );    /* Column name, just add it.          */
               gal_list_str_add(toread, str, 1);
               node->index=*totcalled;
diff --git a/bin/table/table.c b/bin/table/table.c
index 92e17a2..ed28574 100644
--- a/bin/table/table.c
+++ b/bin/table/table.c
@@ -526,7 +526,7 @@ table_head_tail(struct tableparams *p)
 static void
 table_catcolumn(struct tableparams *p)
 {
-  char *hdu;
+  char *hdu=NULL;
   gal_data_t *tocat, *final;
   gal_list_str_t *filell, *hdull;
   struct gal_options_common_params *cp=&p->cp;
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index f74f009..4a6d355 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -620,6 +620,7 @@ Gnuastro library
 * Convolution functions::       Library functions to do convolution.
 * Interpolation::               Interpolate (over blank values possibly).
 * Git wrappers::                Wrappers for functions in libgit2.
+* Unit conversion library (@file{units.h})::  Convert between units.
 * Spectral lines library::      Functions for operating on Spectral lines.
 * Cosmology library::           Cosmological calculations.
 
@@ -3113,7 +3114,7 @@ In column-arithmetic, you can identify columns by number 
or name, see @ref{Colum
 
 @example
 $ asttable cat/xdf-f160w-f105w.fits -ocat/f105w-f160w.fits \
-           -c1,2,RA,DEC,"arith MAG_F105W MAG_F160W -"      \
+           -c1,2,RA,DEC,'arith MAG_F105W MAG_F160W -'      \
            --range=SN_F160W,7,inf
 @end example
 
@@ -9094,31 +9095,54 @@ Just note that white-space characters are used between 
the tokens of the arithme
 Therefore the whole expression (including the activation word) has to be 
quoted on the command-line or in a shell script (see the examples below).
 
 To identify a column you can directly use its name, or specify its number 
(counting from one, see @ref{Selecting table columns}).
-When you are giving a column number, it is necessary to prefix it with a 
@code{c} (otherwise it is not distinguishable from a constant number to use in 
the arithmetic operation).
+When you are giving a column number, it is necessary to prefix the number with 
a @code{$}, similar to AWK.
+Otherwise the number is not distinguishable from a constant number to use in 
the arithmetic operation.
 
 For example with the command below, the first two columns of @file{table.fits} 
will be printed along with a third column that is the result of multiplying the 
first column with @mymath{10^{10}} (for example to convert wavelength from 
Meters to Angstroms).
-Note how without the `@key{c}', it is not possible to distinguish between 
@key{1} as a column-counter, or as a constant number to use in the arithmetic 
operation.
+Note that without the `@key{$}', it is not possible to distinguish between 
``1'' as a column-counter, or as a constant number to use in the arithmetic 
operation.
+Also note that because of the significance of @key{$} for the command-line 
environment, the single-quotes are used here (as in an AWK expression), not 
double-quotes.
 
 @example
-$ asttable table.fits -c1,2 -c"arith c1 1e10 x"
+$ asttable table.fits -c1,2 -c'arith $1 1e10 x'
 @end example
 
+@cartouche
+@noindent
+@strong{Single quotes when string contains @key{$}}: On the command-line, or 
in shell-scripts, @key{$} is used to expand variables, for example @code{echo 
$PATH} prints the value (a string of characters) in the variable @code{PATH}, 
it will not simply print @code{$PATH}.
+This operation is also permitted within double quotes, so @code{echo "$PATH"} 
will produce the same output.
+This is good when printing values, for example in the command below, 
@code{$PATH} will expand to the value within it.
+
+@example
+$ echo "My path is: $PATH"
+@end example
+
+If you actually want to return the literal string @code{$PATH}, not the value 
in the @code{PATH} variable (like the scenario here in column arithmetic), you 
should put it in single quotes like below.
+The printed value here will include the @code{$}, please try it to see for 
your self and compare to above.
+
+@example
+$ echo 'My path is: $PATH'
+@end example
+
+Therefore, when your column arithmetic involves the @key{$} sign (to specify 
columns by number), quote your @code{arith } string with a single quotation 
mark.
+Otherwise you can use both single or double quotes.
+@end cartouche
+
 Alternatively, if the columns have meta-data and the first two are 
respectively called @code{AWAV} and @code{SPECTRUM}, the command above is 
equivalent to the command below.
 Note that the @key{c} is no longer necessary in this scenario.
 
 @example
-$ asttable table.fits -cAWAV,SPECTRUM -c"arith AWAV 1e10 x"
+$ asttable table.fits -cAWAV,SPECTRUM -c'arith AWAV 1e10 x'
 @end example
 
 Comparison of the two commands above clearly shows why it is recommended to 
use column names instead of numbers.
-When the columns have clear names, the command/script actually becomes much 
more readable, describing the intent of the operation.
+When the columns have descriptive names, the command/script actually becomes 
much more readable, describing the intent of the operation.
 It is also independent of the low-level table structure: for the second 
command, the position of the @code{AWAV} and @code{SPECTRUM} columns in 
@file{table.fits} is irrelevant.
 
 Finally, since the arithmetic expressions are a value to @option{--column}, it 
doesn't necessarily have to be a separate option, so the commands above are 
also identical to the command below (note that this only has one @option{-c} 
option).
 Just be very careful with the quoting!
 
 @example
-$ asttable table.fits -cAWAV,SPECTRUM,"arith AWAV 1e10 x"
+$ asttable table.fits -cAWAV,SPECTRUM,'arith AWAV 1e10 x'
 @end example
 
 Almost all the arithmetic operators of @ref{Arithmetic operators} are also 
supported for column arithmetic in Table.
@@ -9139,10 +9163,10 @@ The first three columns are the input table's ID, RA 
and Dec columns.
 The fourth and fifth columns will be the pixel positions in @file{image.fits} 
that correspond to each RA and Dec.
 
 @example
-$ asttable table.fits -cID,RA,DEC,"arith RA DEC wcstoimg" \
+$ asttable table.fits -cID,RA,DEC,'arith RA DEC wcstoimg' \
            --wcsfile=image.fits
 $ asttable table.fits -cID,RA -cDEC \
-           -c"arith RA DEC wcstoimg" --wcsfile=image.fits
+           -c'arith RA DEC wcstoimg' --wcsfile=image.fits
 @end example
 
 @item imgtowcs
@@ -9158,11 +9182,11 @@ In other words, the following commands are all valid:
 
 @example
 $ asttable table.fits \
-           -c"arith RA1 DEC1 RA2 DEC2 angular-distance"
+           -c'arith RA1 DEC1 RA2 DEC2 angular-distance'
 $ asttable table.fits \
-           -c"arith RA DEC 12.345 6.789 angular-distance"
+           -c'arith RA DEC 12.345 6.789 angular-distance'
 $ asttable table.fits \
-           -c"arith 12.345 6.789 RA DEC angular-distance"
+           -c'arith 12.345 6.789 RA DEC angular-distance'
 @end example
 
 In the first case we are assuming that @file{table.fits} has the following 
four columns @code{RA1}, @code{DEC1}, @code{RA2}, @code{DEC2}.
@@ -9176,6 +9200,31 @@ The distance (along a great circle) on a sphere between 
two points is calculated
 
 @dispmath {\cos(d)=\sin(d_1)\sin(d_2)+\cos(d_1)\cos(d_2)\cos(r_1-r_2)}
 
+@item ra-to-degree
+Convert the hour-wise Right Ascension (RA) string, in the format of 
@code{HH:MM:SS}, to degrees.
+Note that the input column has to be an string format.
+In FITS tables, string columns are well-defined.
+For plain-text tables, please follow the standards defined in @ref{Gnuastro 
text table format}, otherwise the string column won't be read.
+@example
+$ asttable catalog.fits -c'arith RA ra-to-degree'
+$ asttable catalog.fits -c'arith $5 ra-to-degree'
+@end example
+
+@item dec-to-degree
+Convert the Declination (Dec) string, in the format of @code{DD:MM:SS}, to 
degrees (a single floating point number).
+For more details please see the @option{ra-to-degree} operator.
+
+@item degree-to-ra
+@cindex Right Ascension
+Convert degrees (a column with a single floating point number) to the Right 
Ascension, RA, string (in the format of @code{HH:MM:SS}).
+The output will be a string column so no further mathematical operations can 
be done on it.
+The output can be in any format (for example FITS or plain-text).
+If its plain-text, the string column will be written following the standards 
described in @ref{Gnuastro text table format}.
+
+@item degree-to-dec
+@cindex Declination
+Convert degrees (a column with a single floating point number) to the 
Declination, Dec, string (in the format of @code{DD:MM:SS}).
+See the @option{degree-to-ra} for more on the format of the output.
 @end table
 
 
@@ -9216,14 +9265,14 @@ $ asttable bintab.fits --range=10,10e5,inf
 
 ## Only print the 2nd column, and the third column multiplied by 5,
 ## Save the resulting two columns in `table.txt'
-$ asttable bintab.fits -c2,"arith c2 5 x" -otable.fits
+$ asttable bintab.fits -c2,'arith $2 5 x' -otable.fits
 
 ## Sort the output columns by the third column, save output:
 $ asttable bintab.fits --sort=3 -ooutput.txt
 
 ## Subtract the first column from the second in `cat.txt' (can also
 ## be a FITS table) and keep the third and fourth columns.
-$ asttable cat.txt -c"arith c2 c1 -",3,4 -ocat.fits
+$ asttable cat.txt -c'arith $2 c1 -',3,4 -ocat.fits
 @end example
 
 Table's input dataset can be given either as a file or from Standard input 
(see @ref{Standard input}).
@@ -18271,6 +18320,7 @@ If you use the Info version of this manual (see 
@ref{Info}), you don't have to w
 * Convolution functions::       Library functions to do convolution.
 * Interpolation::               Interpolate (over blank values possibly).
 * Git wrappers::                Wrappers for functions in libgit2.
+* Unit conversion library (@file{units.h})::  Convert between units.
 * Spectral lines library::      Functions for operating on Spectral lines.
 * Cosmology library::           Cosmological calculations.
 @end menu
@@ -22252,6 +22302,17 @@ different type, you can convert the input to a 
floating point type with
 @code{gal_data_copy_to_new_type_free}(see @ref{Copying datasets}).
 @end deffn
 
+@deffn  Macro GAL_ARITHMETIC_OP_RA_TO_DEGREE
+@deffnx Macro GAL_ARITHMETIC_OP_DEC_TO_DEGREE
+@deffnx Macro GAL_ARITHMETIC_OP_DEGREE_TO_RA
+@deffnx Macro GAL_ARITHMETIC_OP_DEGREE_TO_DEC
+@cindex Declination
+@cindex Right Ascension
+Unary operators to convert between degrees (as a single floating point number) 
to the standard Right Ascension and Declination notation (as strings, 
respectively in the format of @code{HH:MM:SS} and @code{DD:MM:SS}).
+The first two operators expect a string operand and will return a 
double-precision floating point operand.
+The latter two are the opposite.
+@end deffn
+
 @deffn  Macro GAL_ARITHMETIC_OP_MINVAL
 @deffnx Macro GAL_ARITHMETIC_OP_MAXVAL
 @deffnx Macro GAL_ARITHMETIC_OP_NUMBERVAL
@@ -24659,7 +24720,7 @@ blank. To see if any blank (non-interpolated) elements 
remain, you can use
 @end deftypefun
 
 
-@node Git wrappers, Spectral lines library, Interpolation, Gnuastro library
+@node Git wrappers, Unit conversion library (@file{units.h}), Interpolation, 
Gnuastro library
 @subsection Git wrappers (@file{git.h})
 
 @cindex Git
@@ -24695,12 +24756,46 @@ not installed or the program calling this function is 
not within a version
 controlled directory, then the output will be the @code{NULL} pointer.
 @end deftypefun
 
-@node Spectral lines library, Cosmology library, Git wrappers, Gnuastro library
+@node Unit conversion library (@file{units.h}), Spectral lines library, Git 
wrappers, Gnuastro library
+@subsection Unit conversion library (@file{units.h})
+
+Datasets can contain values in various formats or units.
+The functions in this section are defined to facilitate the easy conversion 
between them and are declared in @file{units.h}.
+If there are certain conversions that are useful for your work, please get in 
touch.
+
+@deftypefun int gal_units_extract_decimal (char @code{*convert}, const char 
@code{*delimiter}, double @code{*args}, size_t @code{n})
+Parse the input @code{convert} string with a certain delimiter (for example 
@code{01:23:45}, where the delimiter is @code{":"}) as multiple numbers (for 
example 1,23,45) and write them as an array in the space that @code{args} is 
pointing to.
+The expected number of values in the string is specified by the @code{n} 
argument (3 in the example above).
+
+If the function succeeds, it will return 1, otherwise it will return 0 and the 
values may not be fully written into @code{args}.
+If the number of values parsed in the string is different from @code{n}, this 
function will fail.
+@end deftypefun
+
+@deftypefun double gal_units_ra_to_degree (char @code{*convert})
+@cindex Right Ascension
+Convert the input Right Ascension (RA) string (in the format of 
@code{HH:MM:SS}) to degrees (a single floating point number).
+@end deftypefun
+
+@deftypefun double gal_units_dec_to_degree (char @code{*convert})
+@cindex Declination
+Convert the input Declination (Dec) string (in the format of @code{DD:MM:SS}) 
to degrees (a single floating point number).
+@end deftypefun
+
+@deftypefun {char *} gal_units_degree_to_ra (double @code{decimal})
+@cindex Right Ascension
+Convert the input Right Ascension (RA) degree (a single floating point number) 
to old/standard notation (in the format of @code{HH:MM:SS}).
+@end deftypefun
+
+@deftypefun {char *} gal_units_degree_to_dec (double @code{decimal})
+@cindex Declination
+Convert the input Declination (RA) degree (a single floating point number) to 
old/standard notation (in the format of @code{HH:MM:SS}).
+@end deftypefun
+
+@node Spectral lines library, Cosmology library, Unit conversion library 
(@file{units.h}), Gnuastro library
 @subsection Spectral lines library (@file{speclines.h})
 
-Gnuastro's library has the following macros and functions for dealing with
-spectral lines. All these functions are declared in
-@file{gnuastro/spectra.h}.
+Gnuastro's library has the following macros and functions for dealing with 
spectral lines.
+All these functions are declared in @file{gnuastro/spectra.h}.
 
 @cindex H-alpha
 @cindex H-beta
diff --git a/lib/arithmetic.c b/lib/arithmetic.c
index 5367c40..8b8ab86 100644
--- a/lib/arithmetic.c
+++ b/lib/arithmetic.c
@@ -493,10 +493,10 @@ arithmetic_unary_function(int operator, int flags, 
gal_data_t *in)
      floating point type, its not useful.*/
   if( (flags & GAL_ARITHMETIC_INPLACE)
       && (in->type==GAL_TYPE_FLOAT32 || in->type==GAL_TYPE_FLOAT64)
-      && (operator != GAL_ARITHMETIC_CONVERT_DECIMAL_RA
-      &&  operator != GAL_ARITHMETIC_CONVERT_DECIMAL_DEC
-      &&  operator != GAL_ARITHMETIC_CONVERT_RA_DECIMAL
-      &&  operator != GAL_ARITHMETIC_CONVERT_DEC_DECIMAL ) )
+      && (operator != GAL_ARITHMETIC_OP_RA_TO_DEGREE
+      &&  operator != GAL_ARITHMETIC_OP_DEC_TO_DEGREE
+      &&  operator != GAL_ARITHMETIC_OP_DEGREE_TO_RA
+      &&  operator != GAL_ARITHMETIC_OP_DEGREE_TO_DEC ) )
     inplace=1;
 
   if(inplace)
@@ -511,12 +511,12 @@ arithmetic_unary_function(int operator, int flags, 
gal_data_t *in)
                 : GAL_TYPE_FLOAT32 );
 
       /* Check for operators which have fixed output types */
-      if ( operator == GAL_ARITHMETIC_CONVERT_RA_DECIMAL ||
-           operator == GAL_ARITHMETIC_CONVERT_DEC_DECIMAL )
+      if ( operator == GAL_ARITHMETIC_OP_RA_TO_DEGREE ||
+           operator == GAL_ARITHMETIC_OP_DEC_TO_DEGREE )
         otype = GAL_TYPE_FLOAT64;
 
-      if (operator == GAL_ARITHMETIC_CONVERT_DECIMAL_RA ||
-          operator == GAL_ARITHMETIC_CONVERT_DECIMAL_DEC)
+      if (operator == GAL_ARITHMETIC_OP_DEGREE_TO_RA ||
+          operator == GAL_ARITHMETIC_OP_DEGREE_TO_DEC)
         otype = GAL_TYPE_STRING;
 
       o = gal_data_alloc(NULL, otype, in->ndim, in->dsize, in->wcs,
@@ -539,20 +539,20 @@ arithmetic_unary_function(int operator, int flags, 
gal_data_t *in)
       UNIARY_FUNCTION_ON_ELEMENT( log10 );
       break;
 
-    case GAL_ARITHMETIC_CONVERT_RA_DECIMAL:
-      UNIFUNC_RUN_FUNCTION_ON_ELEMENT_STRING( double, gal_units_ra_to_decimal  
);
+    case GAL_ARITHMETIC_OP_RA_TO_DEGREE:
+      UNIFUNC_RUN_FUNCTION_ON_ELEMENT_STRING(double, gal_units_ra_to_degree);
       break;
 
-    case GAL_ARITHMETIC_CONVERT_DEC_DECIMAL:
-      UNIFUNC_RUN_FUNCTION_ON_ELEMENT_STRING( double, gal_units_dec_to_decimal 
 );
+    case GAL_ARITHMETIC_OP_DEC_TO_DEGREE:
+      UNIFUNC_RUN_FUNCTION_ON_ELEMENT_STRING(double, gal_units_dec_to_degree);
       break;
 
-    case GAL_ARITHMETIC_CONVERT_DECIMAL_RA:
-      UNIARY_FUNCTION_ON_ELEMENT_OUTPUT_STRING( gal_units_decimal_to_ra );
+    case GAL_ARITHMETIC_OP_DEGREE_TO_RA:
+      UNIARY_FUNCTION_ON_ELEMENT_OUTPUT_STRING(gal_units_degree_to_ra);
       break;
 
-    case GAL_ARITHMETIC_CONVERT_DECIMAL_DEC:
-      UNIARY_FUNCTION_ON_ELEMENT_OUTPUT_STRING( gal_units_decimal_to_dec );
+    case GAL_ARITHMETIC_OP_DEGREE_TO_DEC:
+      UNIARY_FUNCTION_ON_ELEMENT_OUTPUT_STRING(gal_units_degree_to_dec);
       break;
 
     default:
@@ -1815,14 +1815,14 @@ gal_arithmetic_set_operator(char *string, size_t 
*num_operands)
     { op=GAL_ARITHMETIC_OP_LOG10;             *num_operands=1;  }
 
   /* Units conversion functions */
-  else if (!strcmp(string, "ra-to-decimal"))
-    { op=GAL_ARITHMETIC_CONVERT_RA_DECIMAL;   *num_operands=1;  }
-  else if (!strcmp(string, "dec-to-decimal"))
-    { op=GAL_ARITHMETIC_CONVERT_DEC_DECIMAL;  *num_operands=1;  }
-  else if (!strcmp(string, "decimal-to-ra"))
-    { op=GAL_ARITHMETIC_CONVERT_DECIMAL_RA;   *num_operands=1;  }
-  else if (!strcmp(string, "decimal-to-dec"))
-    { op = GAL_ARITHMETIC_CONVERT_DECIMAL_DEC;*num_operands=1;  }
+  else if (!strcmp(string, "ra-to-degree"))
+    { op=GAL_ARITHMETIC_OP_RA_TO_DEGREE;   *num_operands=1;  }
+  else if (!strcmp(string, "dec-to-degree"))
+    { op=GAL_ARITHMETIC_OP_DEC_TO_DEGREE;  *num_operands=1;  }
+  else if (!strcmp(string, "degree-to-ra"))
+    { op=GAL_ARITHMETIC_OP_DEGREE_TO_DEC;  *num_operands=1;  }
+  else if (!strcmp(string, "degree-to-dec"))
+    { op=GAL_ARITHMETIC_OP_DEGREE_TO_DEC;  *num_operands=1;  }
 
   /* Statistical/higher-level operators. */
   else if (!strcmp(string, "minvalue"))
@@ -1974,10 +1974,10 @@ gal_arithmetic_operator_string(int operator)
     case GAL_ARITHMETIC_OP_LOG:             return "log";
     case GAL_ARITHMETIC_OP_LOG10:           return "log10";
 
-    case GAL_ARITHMETIC_CONVERT_RA_DECIMAL: return "ra-to-decimal";
-    case GAL_ARITHMETIC_CONVERT_DEC_DECIMAL:return "dec-to-decimal";
-    case GAL_ARITHMETIC_CONVERT_DECIMAL_RA: return "decimal-to-ra";
-    case GAL_ARITHMETIC_CONVERT_DECIMAL_DEC:return "decimal-to-dec";
+    case GAL_ARITHMETIC_OP_RA_TO_DEGREE:    return "ra-to-degree";
+    case GAL_ARITHMETIC_OP_DEC_TO_DEGREE:   return "dec-to-degree";
+    case GAL_ARITHMETIC_OP_DEGREE_TO_RA:    return "degree-to-ra";
+    case GAL_ARITHMETIC_OP_DEGREE_TO_DEC:   return "degree-to-dec";
 
     case GAL_ARITHMETIC_OP_MINVAL:          return "minvalue";
     case GAL_ARITHMETIC_OP_MAXVAL:          return "maxvalue";
@@ -2077,10 +2077,10 @@ gal_arithmetic(int operator, size_t numthreads, int 
flags, ...)
     case GAL_ARITHMETIC_OP_SQRT:
     case GAL_ARITHMETIC_OP_LOG:
     case GAL_ARITHMETIC_OP_LOG10:
-    case GAL_ARITHMETIC_CONVERT_RA_DECIMAL:
-    case GAL_ARITHMETIC_CONVERT_DEC_DECIMAL:
-    case GAL_ARITHMETIC_CONVERT_DECIMAL_RA:
-    case GAL_ARITHMETIC_CONVERT_DECIMAL_DEC:
+    case GAL_ARITHMETIC_OP_RA_TO_DEGREE:
+    case GAL_ARITHMETIC_OP_DEC_TO_DEGREE:
+    case GAL_ARITHMETIC_OP_DEGREE_TO_RA:
+    case GAL_ARITHMETIC_OP_DEGREE_TO_DEC:
       d1 = va_arg(va, gal_data_t *);
       out=arithmetic_unary_function(operator, flags, d1);
       break;
diff --git a/lib/gnuastro/arithmetic.h b/lib/gnuastro/arithmetic.h
index f39fc1e..151c4ab 100644
--- a/lib/gnuastro/arithmetic.h
+++ b/lib/gnuastro/arithmetic.h
@@ -106,10 +106,10 @@ enum gal_arithmetic_operators
   GAL_ARITHMETIC_OP_LOG,          /* log()   */
   GAL_ARITHMETIC_OP_LOG10,        /* log10() */
 
-  GAL_ARITHMETIC_CONVERT_RA_DECIMAL,    /* right ascension to decimal      */
-  GAL_ARITHMETIC_CONVERT_DEC_DECIMAL,   /* declination to decimal          */
-  GAL_ARITHMETIC_CONVERT_DECIMAL_RA,    /* right ascension to decimal      */
-  GAL_ARITHMETIC_CONVERT_DECIMAL_DEC,   /* declination to decimal          */
+  GAL_ARITHMETIC_OP_RA_TO_DEGREE, /* right ascension to decimal      */
+  GAL_ARITHMETIC_OP_DEC_TO_DEGREE,/* declination to decimal          */
+  GAL_ARITHMETIC_OP_DEGREE_TO_RA, /* right ascension to decimal      */
+  GAL_ARITHMETIC_OP_DEGREE_TO_DEC,/* declination to decimal          */
 
   GAL_ARITHMETIC_OP_MINVAL,       /* Minimum value of array.               */
   GAL_ARITHMETIC_OP_MAXVAL,       /* Maximum value of array.               */
diff --git a/lib/gnuastro/units.h b/lib/gnuastro/units.h
index 952e141..e5eb401 100644
--- a/lib/gnuastro/units.h
+++ b/lib/gnuastro/units.h
@@ -57,25 +57,22 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 
 
 
+int
+gal_units_extract_decimal(char *convert, const char *delimiter,
+                          double *args, size_t n);
 
-/*************************************************************
- **************     Convert units to decimal   ***************
- *************************************************************/
 double
-gal_units_ra_to_decimal (char *convert);
+gal_units_ra_to_degree (char *convert);
 
 double
-gal_units_dec_to_decimal (char *convert);
+gal_units_dec_to_degree (char *convert);
 
-/*************************************************************
- **************     Convert decimal to units   ***************
- *************************************************************/
 char *
-gal_units_decimal_to_ra (double decimal);
+gal_units_degree_to_ra (double decimal);
 
 char *
-gal_units_decimal_to_dec (double decimal);
+gal_units_degree_to_dec (double decimal);
 
 __END_C_DECLS    /* From C++ preparations */
 
-#endif           /* __GAL_UNITS_H__ */
\ No newline at end of file
+#endif           /* __GAL_UNITS_H__ */
diff --git a/lib/units.c b/lib/units.c
index e23fc35..eb672f1 100644
--- a/lib/units.c
+++ b/lib/units.c
@@ -24,73 +24,70 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <config.h>
 
 #include <math.h>
+#include <errno.h>
+#include <error.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <error.h>
-
 
+#include <gnuastro/type.h>
+#include <gnuastro/pointer.h>
 
 
 
 /**********************************************************************/
 /****************      Functions to parse strings     *****************/
 /**********************************************************************/
-
-
 /* Parse the input string consisting of numbers separated by given
- * delimiter into an array. */
+   delimiter into an array. */
 int
-gal_units_extract_decimal (char *convert, const char *delimiter,
-                           double *args, size_t n)
+gal_units_extract_decimal(char *convert, const char *delimiter,
+                          double *args, size_t n)
 {
-  char *copy, *token, *end;
   size_t i = 0;
-  /* Create a copy of the string to be parsed */
-  copy = strdup (convert);
+  char *copy, *token, *end;
 
+  /* Create a copy of the string to be parsed and parse it. This is because
+     it will be modified during the parsing. */
+  copy=strdup(convert);
   do
     {
       /* Check if the required number of arguments are passed */
-      if (i == n + 1)
+      if(i==n+1)
         {
-          free (copy);
-          error (0, 0, "'%s' exceeds maximum number of "
-                       "arguments\n", convert);
+          free(copy);
+          error(0, 0, "%s: input '%s' exceeds maximum number of arguments "
+                "(%zu)", __func__, convert, n);
           return 0;
         }
 
-
       /* Extract the substring till the next delimiter */
-      token = strtok (i == 0 ? copy : NULL, delimiter);
-
-      if (token)
+      token=strtok(i==0?copy:NULL, delimiter);
+      if(token)
         {
-          /* Parse extracted string as a number */
+          /* Parse extracted string as a number, and check if it worked. */
           args[i++] = strtod (token, &end);
-          /* Check if strtod fails to parse any character in substring */
-          if (*end && *end != delimiter)
+          if (*end && *end != *delimiter)
             {
-              free (copy);
-              error (0, 0, "Unable to parse element %lu in "
-                           "'%s'\n", i, convert);
+              free(copy);
+              error(0, 0, "%s: unable to parse element %zu in '%s'\n",
+                    __func__, i, convert);
               return 0;
             }
         }
-
     }
-  while (token && *token);
-
+  while(token && *token);
   free (copy);
-  /* Check if the number of elements parsed is unequal to numbers of
-   * elements requested */
+
+  /* Check if the number of elements parsed. */
   if (i != n)
     {
-      error (0, 0, "`%s' must contain %lu numbers, but has "
-                   "%lu numbers\n", convert, n, i);
+      error (0, 0, "%s: input `%s' must contain %lu numbers, but has "
+             "%lu numbers\n", __func__, convert, n, i);
       return 0;
     }
 
+  /* Numbers are written, return successfully. */
   return 1;
 }
 
@@ -115,92 +112,97 @@ gal_units_extract_decimal (char *convert, const char 
*delimiter,
 /****************      Convert string to decimal      *****************/
 /**********************************************************************/
 
-
 /* Parse the right ascension input as a string in form of hh:mm:ss to a
  * single decimal value calculated by (hh + mm / 60 + ss / 3600 ) * 15. */
 double
-gal_units_ra_to_decimal (char *convert)
+gal_units_ra_to_degree(char *convert)
 {
   double val[3];
-  double decimal = 0.0;
+  double decimal=0.0;
 
   /* Check whether the string is successfully parsed */
-  if (gal_units_extract_decimal (convert, ":", val, 3))
+  if(gal_units_extract_decimal (convert, ":", val, 3))
     {
-      /* Check whether value of hours is in within limits */
-      if (val[0] < 0.0 || val[0] > 24.0)
+      /* Check whether the first value is in within limits, and add it. */
+      if(val[0]<0.0 || val[0]>24.0)
         {
-          error (0, 0, "Error: Value of hours should be "
-                       "between be 0 and 24. %s\n", convert);
+          error(0, 0, "%s: value of first decimal (%g) in `%s' should be "
+                "between 0 and 24", __func__, val[0], convert);
           return NAN;
         }
-      /* Add hours to the decimal value */
       decimal += val[0];
 
-      /* Check whether value of minutes is in within limits */
-      if (val[1] < 0.0 || val[1] > 60.0)
+      /* Check whether value of minutes is in within limits, and add it. */
+      if(val[1]<0.0 || val[1]>60.0)
         {
-          error (0, 0, "Error: Value of minutes should be "
-                       "between be 0 and 60. %s\n", convert);
+          error(0, 0, "%s: value of second decimal (%g) in `%s' should be "
+                "between 0 and 60", __func__, val[0], convert);
           return NAN;
         }
-      /* Convert minutes to hours and add to the decimal value */
       decimal += val[1] / 60;
 
-      /* Check whether value of seconds is in within limits */
-      if (val[2] < 0.0 || val[2] > 60.0)
+      /* Check whether value of seconds is in within limits, and add it. */
+      if(val[2]<0.0 || val[2]>60.0)
         {
-          error (0, 0, "Error: Value of seconds should be "
-                       "between be 0 and 60. %s\n", convert);
+          error(0, 0, "%s: value of third decimal (%g) in `%s' should be "
+                "between 0 and 60", __func__, val[0], convert);
           return NAN;
         }
-      /* Convert seconds to hours and add to the decimal value */
       decimal += val[2] / 3600;
 
-      /* Convert value to decimal */
+      /* Convert value to degrees and return. */
       decimal *= 15.0;
-
       return decimal;
     }
   else
-    return NAN;
+    {
+      error(0, 0, "%s: input `%s' couldn't be parsed", __func__, convert);
+      return NAN;
+    }
+
+  /* Control shouldn't reach this point. If it does, its a bug! */
+  error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix the "
+        "problem. Control should not reach the end of this function",
+        __func__, PACKAGE_BUGREPORT);
+  return NAN;
 }
 
+
+
+
+
 /* Parse the declination input as a string in form of dd:mm:ss to a decimal
  * calculated by (dd + mm / 60 + ss / 3600 ). */
 double
-gal_units_dec_to_decimal (char *convert)
+gal_units_dec_to_degree (char *convert)
 {
-  double val[3];
-  double decimal = 0.0;
-  int sign = 1;
+  int sign;
+  double val[3], decimal=0.0;
 
-  if (gal_units_extract_decimal (convert, ":", val, 3))
+  /* Parse the values in the input string. */
+  if(gal_units_extract_decimal (convert, ":", val, 3))
     {
-      /* Check whether value of decimal is in within limits */
-      if (val[0] < -90.0 || val[0] > 90.0)
+      /* Check whether the first value is in within limits. */
+      if(val[0]<-90.0 || val[0]>90.0)
         {
-          error (0, 0, "Error: Value of decimal should be "
-                       "between be -90 and 90. %s\n", convert);
+          error(0, 0, "%s: value of first decimal (%g) in `%s' should be "
+                "between -90 and 90", __func__, val[0], convert);
           return NAN;
         }
 
       /* If declination is negative, the first value in the array will be
-       * negative and all other values will be positive. In that case, we
-       * set sign equal to -1. Therefore, we multiply the first value by
-       * sign to make it positive. The final answer is again multiplied by
-       * sign to make its sign same as original. */
-      if (val[0] < 0.0)
-        sign = -1;
-
-      /* Add decimal to the decimal value after making it positive */
+         negative and all other values will be positive. In that case, we
+         set sign equal to -1. Therefore, we multiply the first value by
+         sign to make it positive. The final answer is again multiplied by
+         sign to make its sign same as original. */
+      sign = val[0]<0.0 ? -1 : 1;
       decimal += val[0] * sign;
 
-      /* Check whether value of arc-minutes is in within limits */
-      if (val[1] < 0.0 || val[1] > 60.0)
+      /* Check whether value of arc-minutes is in within limits. */
+      if(val[1]<0.0 || val[1]>60.0)
         {
-          error (0, 0, "Error: Value of arc-minutes should be "
-                       "between be 0 and 60. %s\n", convert);
+          error(0, 0, "%s: value of second decimal (%g) in `%s' should be "
+                "between 0 and 60", __func__, val[1], convert);
           return NAN;
         }
       /* Convert arc-minutes to decimal and add to the decimal value */
@@ -209,20 +211,29 @@ gal_units_dec_to_decimal (char *convert)
       /* Check whether value of arc-seconds is in within limits */
       if (val[2] < 0.0 || val[2] > 60.0)
         {
-          error (0, 0, "Error: Value of arc-seconds should be "
-                       "between be 0 and 60. %s\n", convert);
+          error(0, 0, "%s: value of third decimal (%g) in `%s' should be "
+                "between 0 and 60", __func__, val[2], convert);
           return NAN;
         }
+
       /* Convert arc-seconds to decimal and add to the decimal value */
       decimal += val[2] / 3600;
 
-      /* Make the sign of the decimal value same as input */
+      /* Make the sign of the decimal value same as input and return. */
       decimal *= sign;
-
       return decimal;
     }
   else
-    return NAN;
+    {
+      error(0, 0, "%s: input `%s' couldn't be parsed", __func__, convert);
+      return NAN;
+    }
+
+  /* Control shouldn't reach this point. If it does, its a bug! */
+  error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix the "
+        "problem. Control should not reach the end of this function",
+        __func__, PACKAGE_BUGREPORT);
+  return NAN;
 }
 
 
@@ -241,100 +252,117 @@ gal_units_dec_to_decimal (char *convert)
 
 
 
+
+
+
 /**********************************************************************/
 /****************      Convert decimal to string      *****************/
 /**********************************************************************/
 
+/* Max-length of output string. */
+#define UNITS_RADECSTR_MAXLENGTH 50
 
 /* Parse the right ascension input as a decimal to a string in form of
- * hh:mm:ss.ss . */
+   hh:mm:ss.ss . */
 char *
-gal_units_decimal_to_ra (double decimal)
+gal_units_degree_to_ra(double decimal)
 {
-  int hours = 0, minutes = 0;
-  float seconds = 0.0; /* For sub-second accuracy */
+  size_t nchars;
+  int hours=0, minutes=0;
+  float seconds=0.0; /* For sub-second accuracy */
+
   /* Allocate string of length 15 which is large enough for string of
-   * format hh:mm:ss.ss and sign */
-  char *ra = ( char * ) malloc (sizeof (char) * 15);
+     format hh:mm:ss.ss and sign */
+  char *ra=gal_pointer_allocate(GAL_TYPE_UINT8, UNITS_RADECSTR_MAXLENGTH,
+                                0, __func__, "ra");
 
   /* Check if decimal value is within bounds otherwise return error */
-  if (decimal < 0 || decimal > 360)
+  if (decimal<0 || decimal>360)
     {
-      error (0, 0, "Error: Value of decimal should be "
-                   "between be 0 and 360. %.10f\n", decimal);
-      return 0;
+      error (0, 0, "%s: value of decimal should be between be 0 and 360, "
+             "but is %g\n", __func__, decimal);
+      return NULL;
     }
 
-  /* Divide decimal value by 15 */
+  /* Divide decimal value by 15 and extract integer part of decimal value
+     to obtain hours */
   decimal /= 15.0;
-
-  /* Extract integer part of decimal value to obtain hours */
-  hours = ( int ) (decimal);
+  hours = (int)decimal;
 
   /* Subtract hours from decimal and multiply remaining value by 60 to
-   * obtain minutes. */
-  minutes = ( int ) ((decimal - hours) * 60);
+     obtain minutes. */
+  minutes = (int)((decimal - hours) * 60);
 
   /* Subtract hours and minutes from decimal and multiply remaining value
-   * by 3600 to obtain seconds. */
+     by 3600 to obtain seconds. */
   seconds = (decimal - hours - minutes / 60.0) * 3600;
 
   /* Format the extracted hours, minutes and seconds as a string with
-   * leading zeros if required, in hh:mm:ss format */
-  snprintf (ra,
-            sizeof (char) * 15, "%02d:%02d:%05.2f", hours, minutes, seconds);
-
+     leading zeros if required, in hh:mm:ss format */
+  nchars = snprintf(ra, UNITS_RADECSTR_MAXLENGTH-1, "%02d:%02d:%g",
+                    hours, minutes, seconds);
+  if(nchars>UNITS_RADECSTR_MAXLENGTH)
+    error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to address "
+          "the problem. The output string has an unreasonable length of "
+          "%zu characters", __func__, PACKAGE_BUGREPORT, nchars);
+
+  /* Return the final string. */
   return ra;
 }
 
+
+
+
+
 /* Parse the declination input as a decimal to a string in form of dd:mm:ss*/
 char *
-gal_units_decimal_to_dec (double decimal)
+gal_units_degree_to_dec(double decimal)
 {
-  int degrees = 0, arc_minutes = 0;
-  float arc_seconds = 0.0;
-  /* Allocate string of length 15 which is large enough for string of
+  size_t nchars;
+  float arc_seconds=0.0;
+  int sign, degrees=0, arc_minutes=0;
+
+  /* Allocate string of fixed length which is large enough for string of
    * format hh:mm:ss.ss and sign */
-  char *dec = ( char * ) malloc (sizeof (char) * 15);
-  int sign = 1;
+  char *dec=gal_pointer_allocate(GAL_TYPE_UINT8, UNITS_RADECSTR_MAXLENGTH,
+                                 0, __func__, "ra");
 
   /* Check if decimal value is within bounds otherwise return error */
-  if (decimal < -90 || decimal > 90)
+  if(decimal<-90 || decimal>90)
     {
-      error (0, 0, "Error: Value of decimal should be "
-                   "between be -90 and 90. %.10f\n", decimal);
-      return 0;
+      error (0, 0, "%s: value of decimal should be between be -90 and 90, "
+             "but is %g\n", __func__, decimal);
+      return NULL;
     }
 
-  /* If declination is negative, we set sign equal to -1. We multiply the
-   * decimal by to make sure it is positive. We then extract degrees,
-   * arc-minutes and arc-seconds from the decimal. Finally, we add a minus
-   * sign in beginning of string if input was negative. */
-  if (decimal < 0)
-    sign = -1;
-
-  /* Multiply decimal by sign to make its positive. */
+  /* If declination is negative, we set `sign' equal to -1. We multiply the
+     decimal by to make sure it is positive. We then extract degrees,
+     arc-minutes and arc-seconds from the decimal. Finally, we add a minus
+     sign in beginning of string if input was negative. */
+  sign = decimal<0.0 ? -1 : 1;
   decimal *= sign;
 
   /* Extract integer part of decimal value to obtain degrees. */
-  degrees = ( int ) (decimal);
+  degrees=(int)decimal;
 
   /* Subtract degrees from decimal and multiply remaining value by 60 to
-   * obtain arc-minutes. */
-  arc_minutes = ( int ) ((decimal - degrees) * 60);
+     obtain arc-minutes. */
+  arc_minutes=(int)( (decimal - degrees) * 60 );
 
   /* Subtract degrees and arc-minutes from decimal and multiply remaining
-   * value by 3600 to obtain arc-seconds. */
+     value by 3600 to obtain arc-seconds. */
   arc_seconds = (decimal - degrees - arc_minutes / 60.0) * 3600;
 
   /* Format the extracted degrees, arc-minutes and arc-seconds as a string
-   * with leading zeros if required, in hh:mm:ss format with correct sign */
-  if (sign < 0)
-    snprintf (dec, sizeof (char)
-                   * 15, "-%02d:%02d:%05.2f", degrees, arc_minutes, 
arc_seconds);
-  else
-    snprintf (dec, sizeof (char)
-                   * 15, "%02d:%02d:%05.2f", degrees, arc_minutes, 
arc_seconds);
-
+     with leading zeros if required, in hh:mm:ss format with correct
+     sign. */
+  nchars = snprintf(dec, UNITS_RADECSTR_MAXLENGTH-1, "%s%02d:%02d:%g",
+                    sign<0?"-":"+", degrees, arc_minutes, arc_seconds);
+  if(nchars>UNITS_RADECSTR_MAXLENGTH)
+    error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to address "
+          "the problem. The output string has an unreasonable length of "
+          "%zu characters", __func__, PACKAGE_BUGREPORT, nchars);
+
+  /* Return the final string. */
   return dec;
-}
\ No newline at end of file
+}



reply via email to

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