[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnuastro-commits] master 81c2b7f 2/2: Dimension collapsing in Arithmeti
From: |
Mohammad Akhlaghi |
Subject: |
[gnuastro-commits] master 81c2b7f 2/2: Dimension collapsing in Arithmetic program and library |
Date: |
Wed, 4 Jul 2018 11:46:38 -0400 (EDT) |
branch: master
commit 81c2b7f9310d6293d250da7f0dcb5068cc005e72
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>
Dimension collapsing in Arithmetic program and library
Three new dimension collapsing operators have been added to the Arithmetic
program and the `dimension.h' library.
---
NEWS | 13 +-
bin/arithmetic/arithmetic.c | 90 +++++++++-
bin/arithmetic/arithmetic.h | 3 +
doc/gnuastro.texi | 109 ++++++++++--
lib/arithmetic.c | 139 +++++++--------
lib/dimension.c | 425 ++++++++++++++++++++++++++++++++++++++++++++
lib/gnuastro/dimension.h | 17 ++
lib/gnuastro/wcs.h | 3 +
lib/wcs.c | 170 ++++++++++++++++++
9 files changed, 883 insertions(+), 86 deletions(-)
diff --git a/NEWS b/NEWS
index 5a359f9..b4c0010 100644
--- a/NEWS
+++ b/NEWS
@@ -5,8 +5,19 @@ GNU Astronomy Utilities NEWS -*-
outline -*-
** New features
+ Arithmetic:
+ - `collapse-sum': collapse/remove a dimension by summing over it.
+ - `collapse-mean': collapse/remove a dimension by averaging over it.
+ - `collapse-number': Number of elements included in the collapse.
+
Table:
- - `--colinfoinstdout': column information when writing to standard output.
+ --colinfoinstdout: column information when writing to standard output.
+
+ Library:
+ - gal_dimension_collapse_sum: collapse/remove a dimension by summing.
+ - gal_dimension_collapse_mean: collapse/remove a dimension by averaging.
+ - gal_dimension_collapse_number: collapse/remove a dimension by number.
+ - gal_wcs_remove_dimension: Remove a dimension in the given WCS structure.
** Removed features
diff --git a/bin/arithmetic/arithmetic.c b/bin/arithmetic/arithmetic.c
index 44ab2e5..f89dbed 100644
--- a/bin/arithmetic/arithmetic.c
+++ b/bin/arithmetic/arithmetic.c
@@ -685,6 +685,82 @@ arithmetic_interpolate(struct arithmeticparams *p, char
*token)
+static void
+arithmetic_collapse(struct arithmeticparams *p, char *token, int operator)
+{
+ long dim;
+ gal_data_t *collapsed=NULL;
+
+ /* First popped operand is the dimension. */
+ gal_data_t *dimension = operands_pop(p, token);
+
+ /* The second popped operand is the desired input dataset. */
+ gal_data_t *input = operands_pop(p, token);
+
+
+ /* Small sanity check. */
+ if( dimension->ndim!=1 || dimension->size!=1)
+ error(EXIT_FAILURE, 0, "First popped operand of `collapse-*' operators "
+ "(dimension to collapse) must be a single number (single-element, "
+ "one-dimensional dataset). But it has %zu dimension(s) and %zu "
+ "element(s).", dimension->ndim, dimension->size);
+ if(dimension->type==GAL_TYPE_FLOAT32 || dimension->type==GAL_TYPE_FLOAT64)
+ error(EXIT_FAILURE, 0, "First popped operand of `collapse-*' operators "
+ "(dimension to collapse) must have an integer type, but it has "
+ "a floating point type (`%s')", gal_type_name(dimension->type,1));
+ dimension=gal_data_copy_to_new_type_free(dimension, GAL_TYPE_LONG);
+ dim=((long *)(dimension->array))[0];
+ if(dim<0 || dim==0)
+ error(EXIT_FAILURE, 0, "First popped operand of `collapse-*' operators "
+ "(dimension to collapse) must be positive (larger than zero), it "
+ "is %ld", dim);
+
+
+ /* If a WCS structure has been read, we'll need to pass it to
+ `gal_dimension_collapse', so it modifies it respectively. */
+ input->wcs=p->refdata.wcs;
+
+
+ /* Run the relevant library function. */
+ switch(operator)
+ {
+ case ARITHMETIC_OP_COLLAPSE_SUM:
+ collapsed=gal_dimension_collapse_sum(input, input->ndim-dim, NULL);
+ break;
+
+ case ARITHMETIC_OP_COLLAPSE_MEAN:
+ collapsed=gal_dimension_collapse_mean(input, input->ndim-dim, NULL);
+ break;
+
+ case ARITHMETIC_OP_COLLAPSE_NUMBER:
+ collapsed=gal_dimension_collapse_number(input, input->ndim-dim);
+ break;
+
+ default:
+ error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix the "
+ "problem. The operator code %d is not recognized", __func__,
+ PACKAGE_BUGREPORT, operator);
+ }
+
+
+ /* If a WCS structure existed, a modified WCS is now present in
+ `collapsed->wcs'. So we'll let the freeing of `input' free the old
+ `p->refdata.wcs' structure and we'll put the new one there, then we'll
+ set `collapsed->wcs' to `NULL', so the new one isn't freed. */
+ p->refdata.wcs = collapsed->wcs;
+ collapsed->wcs = NULL;
+
+
+ /* Clean up and add the collapsed dataset to the top of the operands. */
+ gal_data_free(input);
+ gal_data_free(dimension);
+ operands_add(p, NULL, collapsed);
+}
+
+
+
+
+
@@ -854,7 +930,7 @@ reversepolish(struct arithmeticparams *p)
else if (!strcmp(token->v, "float64"))
{ op=GAL_ARITHMETIC_OP_TO_FLOAT64; nop=1; }
- /* Filters. */
+ /* Library wrappers. */
else if (!strcmp(token->v, "filter-mean"))
{ op=ARITHMETIC_OP_FILTER_MEAN; nop=0; }
else if (!strcmp(token->v, "filter-median"))
@@ -873,6 +949,12 @@ reversepolish(struct arithmeticparams *p)
{ op=ARITHMETIC_OP_INVERT; nop=0; }
else if (!strcmp(token->v, "interpolate-medianngb"))
{ op=ARITHMETIC_OP_INTERPOLATE_MEDIANNGB; nop=0; }
+ else if (!strcmp(token->v, "collapse-sum"))
+ { op=ARITHMETIC_OP_COLLAPSE_SUM; nop=0; }
+ else if (!strcmp(token->v, "collapse-mean"))
+ { op=ARITHMETIC_OP_COLLAPSE_MEAN; nop=0; }
+ else if (!strcmp(token->v, "collapse-number"))
+ { op=ARITHMETIC_OP_COLLAPSE_NUMBER; nop=0; }
/* Finished checks with known operators */
@@ -964,6 +1046,12 @@ reversepolish(struct arithmeticparams *p)
arithmetic_interpolate(p, token->v);
break;
+ case ARITHMETIC_OP_COLLAPSE_SUM:
+ case ARITHMETIC_OP_COLLAPSE_MEAN:
+ case ARITHMETIC_OP_COLLAPSE_NUMBER:
+ arithmetic_collapse(p, token->v, op);
+ break;
+
default:
error(EXIT_FAILURE, 0, "%s: a bug! please contact us at "
"%s to fix the problem. The code %d is not "
diff --git a/bin/arithmetic/arithmetic.h b/bin/arithmetic/arithmetic.h
index e5eca69..4144006 100644
--- a/bin/arithmetic/arithmetic.h
+++ b/bin/arithmetic/arithmetic.h
@@ -40,6 +40,9 @@ enum arithmetic_prog_operators
ARITHMETIC_OP_CONNECTED_COMPONENTS,
ARITHMETIC_OP_INVERT,
ARITHMETIC_OP_INTERPOLATE_MEDIANNGB,
+ ARITHMETIC_OP_COLLAPSE_SUM,
+ ARITHMETIC_OP_COLLAPSE_MEAN,
+ ARITHMETIC_OP_COLLAPSE_NUMBER,
};
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 503d6e8..fa3d408 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -5010,7 +5010,7 @@ line.
@cindex Ubuntu
@cindex @command{apt-get}
@cindex Advanced Packaging Tool (APT, Debian)
-Debian-based GNU/Linux
address@hidden://en.wikipedia.org/wiki/Debian,Debian}-based GNU/Linux
address@hidden@url{https://en.wikipedia.org/wiki/List_of_Linux_distributions#Debian-based}}
(for example Ubuntu or its derivatives) are arguably the largest, and most
used, class of GNU/Linux distributions. All such GNU/Linux distributions
@@ -5028,12 +5028,11 @@ $ sudo apt-get install ghostscript libtool-bin
libjpeg-dev \
@cindex Homebrew
@cindex MacPorts
@cindex @command{brew}
-macOS is the operating system used on Apple devices
-(@url{https://en.wikipedia.org/wiki/MacOS}). macOS does not come with a
-package manager pre-installed, but several widely used, third-party package
-managers exist, such as Homebrew or MacPorts. Both are free
-software. Currently we have only tested Gnuastro's installation with
-Homebrew as described below.
address@hidden://en.wikipedia.org/wiki/MacOS,macOS} is the operating system
+used on Apple devices. macOS does not come with a package manager
+pre-installed, but several widely used, third-party package managers exist,
+such as Homebrew or MacPorts. Both are free software. Currently we have
+only tested Gnuastro's installation with Homebrew as described below.
If not already installed, first obtain Homebrew by following the
instructions at @url{https://brew.sh}. Homebrew manages packages in
@@ -5052,13 +5051,12 @@ $ brew install wcslib
@item @command{pacman} (Arch Linux)
@cindex Arch Linux
@cindex @command{pacman}
-Arch Linux is a smaller GNU/Linux distribution. As discussed in
address@hidden://en.wikipedia.org/wiki/Arch_Linux, Wikipedia}, it follows ``the
-KISS principle ("keep it simple, stupid") as the general guideline, and
-focuses on elegance, code correctness, minimalism and simplicity, and
-expects the user to be willing to make some effort to understand the
-system's operation''. Arch Linux uses ``Package manager'' (Pacman) to
-manage its packages/components.
address@hidden://en.wikipedia.org/wiki/Arch_Linux,Arch Linux} is a smaller
+GNU/Linux distribution, which follows the KISS principle (``keep it simple,
+stupid'') as a general guideline. It ``focuses on elegance, code
+correctness, minimalism and simplicity, and expects the user to be willing
+to make some effort to understand the system's operation''. Arch Linux uses
+``Package manager'' (Pacman) to manage its packages/components.
@example
$ sudo pacman -S ghostscript libtool libjpeg libtiff libgit2 \
\
@@ -11230,6 +11228,55 @@ non-blank neighbors used to calculate the median is
given by the first
popped operand. Note that the distance of the nearest non-blank neighbors
is irrelevant in this interpolation.
address@hidden collapse-sum
+Collapse the given dataset (second popped operand), by summing all elements
+along the first popped operand (a dimension in FITS standard: counting from
+one, from fastest dimension). The returned dataset has one dimension less
+compared to the input.
+
+The output will have a double-precision floating point type irrespective of
+the input dataset's type. Doing the operation in double-precision (64-bit)
+floating point will help the collapse (summation) be affected less by
+floating point errors. But afterwards, single-precision floating points are
+usually enough in real (noisy) datasets. So depending on the type of the
+input and its nature, it is recommended to use one of the type conversion
+operators on the returned dataset.
+
address@hidden World Coordinate System (WCS)
+If any WCS is present, the returned dataset will also lack the respective
+dimension in its WCS matrix. Therefore, when the WCS is important for later
+processing, be sure that the input is aligned with the respective axises: all
non-diagonal elements in the WCS matrix are zero.
+
address@hidden IFU
address@hidden Data cubes
address@hidden 3D data-cubes
address@hidden Cubes (3D data)
address@hidden Narrow-band image
address@hidden Integral field unit (IFU)
+One common application of this operator is the creation of pseudo
+broad-band or narrow-band 2D images from 3D data cubes. For example
+integral field unit (IFU) data products that have two spatial dimensions
+(first two FITS dimensions) and one spectral dimension (third FITS
+dimension). The command below will collapse the whole third dimension into
+a 2D array the size of the first two dimensions, and then convert the
+output to single-precision floating point (as discussed above).
+
address@hidden
+$ astarithmetic cube.fits 3 collapse-sum float32
address@hidden example
+
address@hidden collapse-mean
+Similar to @option{collapse-sum}, but the returned dataset will be the mean
+value along the collapsed dimension, not the sum.
+
address@hidden collapse-number
+Similar to @option{collapse-sum}, but the returned dataset will be the
+number of non-blank values along the collapsed dimension. The output will
+have a 32-bit signed integer type. If the input dataset doesn't have blank
+values, all the elements in the returned dataset will have a single value
+(the length of the collapsed dimension). Therefore this is mostly relevant
+when there are blank values in the dataset.
+
@item erode
@cindex Erosion
Erode the foreground pixels (with value @code{1}) of the input dataset
@@ -22771,6 +22818,40 @@ the two coordinates @code{a} and @code{b} (each an
array of @code{ndim}
elements).
@end deftypefun
address@hidden {gal_data_t *} gal_dimension_collapse_sum (gal_data_t
@code{*in}, size_t @code{c_dim}, gal_data_t @code{*weight})
+Collapse the input dataset (@code{in}) along the given dimension
+(@code{c_dim}, in C definition: starting from zero, from the slowest
+dimension), by summing all elements in that direction. If
address@hidden, it must be a single-dimensional array, with the same
+size as the dimension to be collapsed. The respective weight will be
+multiplied to each element during the collapse.
+
+For generality, the returned dataset will have a @code{GAL_TYPE_FLOAT64}
+type. See @ref{Copying datasets} for converting the returned dataset to a
+desired type. Also, for more on the application of this function, see the
+Arithmetic program's @option{collapse-sum} operator (which uses this
+function) in @ref{Arithmetic operators}.
address@hidden deftypefun
+
address@hidden {gal_data_t *} gal_dimension_collapse_mean (gal_data_t
@code{*in}, size_t @code{c_dim}, gal_data_t @code{*weight})
+Similar to @code{gal_dimension_collapse_sum} (above), but the collapse will
+be done by calculating the mean along the requested dimension, not summing
+over it.
address@hidden deftypefun
+
address@hidden {gal_data_t *} gal_dimension_collapse_number (gal_data_t
@code{*in}, size_t @code{c_dim})
+Collapse the input dataset (@code{in}) along the given dimension
+(@code{c_dim}, in C definition: starting from zero, from the slowest
+dimension), by counting how many non-blank elements there are along that
+dimension.
+
+For generality, the returned dataset will have a @code{GAL_TYPE_INT32}
+type. See @ref{Copying datasets} for converting the returned dataset to a
+desired type. Also, for more on the application of this function, see the
+Arithmetic program's @option{collapse-number} operator (which uses this
+function) in @ref{Arithmetic operators}.
address@hidden deftypefun
+
@deffn {Function-like macro} GAL_DIMENSION_NEIGHBOR_OP (@code{index},
@code{ndim}, @code{dsize}, @code{connectivity}, @code{dinc}, @code{operation})
Parse the neighbors of the element located at @code{index} and do the
requested operation on them. This is defined as a macro to allow easy
diff --git a/lib/arithmetic.c b/lib/arithmetic.c
index 6f31f51..3e84f95 100644
--- a/lib/arithmetic.c
+++ b/lib/arithmetic.c
@@ -183,16 +183,16 @@ arithmetic_not(gal_data_t *data, int flags)
/* Go over the pixels and set the output values. */
switch(data->type)
{
- case GAL_TYPE_UINT8: TYPE_CASE_FOR_NOT(uint8_t); break;
- case GAL_TYPE_INT8: TYPE_CASE_FOR_NOT(int8_t); break;
- case GAL_TYPE_UINT16: TYPE_CASE_FOR_NOT(uint16_t); break;
- case GAL_TYPE_INT16: TYPE_CASE_FOR_NOT(int16_t); break;
- case GAL_TYPE_UINT32: TYPE_CASE_FOR_NOT(uint32_t); break;
- case GAL_TYPE_INT32: TYPE_CASE_FOR_NOT(int32_t); break;
- case GAL_TYPE_UINT64: TYPE_CASE_FOR_NOT(uint64_t); break;
- case GAL_TYPE_INT64: TYPE_CASE_FOR_NOT(int64_t); break;
- case GAL_TYPE_FLOAT32: TYPE_CASE_FOR_NOT(float); break;
- case GAL_TYPE_FLOAT64: TYPE_CASE_FOR_NOT(double); break;
+ case GAL_TYPE_UINT8: TYPE_CASE_FOR_NOT( uint8_t ); break;
+ case GAL_TYPE_INT8: TYPE_CASE_FOR_NOT( int8_t ); break;
+ case GAL_TYPE_UINT16: TYPE_CASE_FOR_NOT( uint16_t ); break;
+ case GAL_TYPE_INT16: TYPE_CASE_FOR_NOT( int16_t ); break;
+ case GAL_TYPE_UINT32: TYPE_CASE_FOR_NOT( uint32_t ); break;
+ case GAL_TYPE_INT32: TYPE_CASE_FOR_NOT( int32_t ); break;
+ case GAL_TYPE_UINT64: TYPE_CASE_FOR_NOT( uint64_t ); break;
+ case GAL_TYPE_INT64: TYPE_CASE_FOR_NOT( int64_t ); break;
+ case GAL_TYPE_FLOAT32: TYPE_CASE_FOR_NOT( float ); break;
+ case GAL_TYPE_FLOAT64: TYPE_CASE_FOR_NOT( double ); break;
case GAL_TYPE_BIT:
error(EXIT_FAILURE, 0, "%s: bit datatypes are not yet supported, "
@@ -1330,63 +1330,63 @@ gal_arithmetic_operator_string(int operator)
{
switch(operator)
{
- case GAL_ARITHMETIC_OP_PLUS: return "+";
- case GAL_ARITHMETIC_OP_MINUS: return "-";
- case GAL_ARITHMETIC_OP_MULTIPLY: return "*";
- case GAL_ARITHMETIC_OP_DIVIDE: return "/";
- case GAL_ARITHMETIC_OP_MODULO: return "%";
-
- case GAL_ARITHMETIC_OP_LT: return "<";
- case GAL_ARITHMETIC_OP_LE: return "<=";
- case GAL_ARITHMETIC_OP_GT: return ">";
- case GAL_ARITHMETIC_OP_GE: return ">=";
- case GAL_ARITHMETIC_OP_EQ: return "==";
- case GAL_ARITHMETIC_OP_NE: return "!=";
- case GAL_ARITHMETIC_OP_AND: return "and";
- case GAL_ARITHMETIC_OP_OR: return "or";
- case GAL_ARITHMETIC_OP_NOT: return "not";
- case GAL_ARITHMETIC_OP_ISBLANK: return "isblank";
- case GAL_ARITHMETIC_OP_WHERE: return "where";
-
- case GAL_ARITHMETIC_OP_BITAND: return "bitand";
- case GAL_ARITHMETIC_OP_BITOR: return "bitor";
- case GAL_ARITHMETIC_OP_BITXOR: return "bitxor";
- case GAL_ARITHMETIC_OP_BITLSH: return "lshift";
- case GAL_ARITHMETIC_OP_BITRSH: return "rshift";
- case GAL_ARITHMETIC_OP_BITNOT: return "bitnot";
-
- case GAL_ARITHMETIC_OP_ABS: return "abs";
- case GAL_ARITHMETIC_OP_POW: return "pow";
- case GAL_ARITHMETIC_OP_SQRT: return "sqrt";
- case GAL_ARITHMETIC_OP_LOG: return "log";
- case GAL_ARITHMETIC_OP_LOG10: return "log10";
-
- case GAL_ARITHMETIC_OP_MINVAL: return "minvalue";
- case GAL_ARITHMETIC_OP_MAXVAL: return "maxvalue";
- case GAL_ARITHMETIC_OP_NUMVAL: return "numvalue";
- case GAL_ARITHMETIC_OP_SUMVAL: return "sumvalue";
- case GAL_ARITHMETIC_OP_MEANVAL: return "meanvalue";
- case GAL_ARITHMETIC_OP_STDVAL: return "stdvalue";
- case GAL_ARITHMETIC_OP_MEDIANVAL: return "medianvalue";
-
- case GAL_ARITHMETIC_OP_MIN: return "min";
- case GAL_ARITHMETIC_OP_MAX: return "max";
- case GAL_ARITHMETIC_OP_NUM: return "num";
- case GAL_ARITHMETIC_OP_SUM: return "sum";
- case GAL_ARITHMETIC_OP_MEAN: return "mean";
- case GAL_ARITHMETIC_OP_STD: return "std";
- case GAL_ARITHMETIC_OP_MEDIAN: return "median";
-
- case GAL_ARITHMETIC_OP_TO_UINT8: return "uchar";
- case GAL_ARITHMETIC_OP_TO_INT8: return "char";
- case GAL_ARITHMETIC_OP_TO_UINT16: return "ushort";
- case GAL_ARITHMETIC_OP_TO_INT16: return "short";
- case GAL_ARITHMETIC_OP_TO_UINT32: return "uint";
- case GAL_ARITHMETIC_OP_TO_INT32: return "int";
- case GAL_ARITHMETIC_OP_TO_UINT64: return "ulong";
- case GAL_ARITHMETIC_OP_TO_INT64: return "long";
- case GAL_ARITHMETIC_OP_TO_FLOAT32: return "float32";
- case GAL_ARITHMETIC_OP_TO_FLOAT64: return "float64";
+ case GAL_ARITHMETIC_OP_PLUS: return "+";
+ case GAL_ARITHMETIC_OP_MINUS: return "-";
+ case GAL_ARITHMETIC_OP_MULTIPLY: return "*";
+ case GAL_ARITHMETIC_OP_DIVIDE: return "/";
+ case GAL_ARITHMETIC_OP_MODULO: return "%";
+
+ case GAL_ARITHMETIC_OP_LT: return "<";
+ case GAL_ARITHMETIC_OP_LE: return "<=";
+ case GAL_ARITHMETIC_OP_GT: return ">";
+ case GAL_ARITHMETIC_OP_GE: return ">=";
+ case GAL_ARITHMETIC_OP_EQ: return "==";
+ case GAL_ARITHMETIC_OP_NE: return "!=";
+ case GAL_ARITHMETIC_OP_AND: return "and";
+ case GAL_ARITHMETIC_OP_OR: return "or";
+ case GAL_ARITHMETIC_OP_NOT: return "not";
+ case GAL_ARITHMETIC_OP_ISBLANK: return "isblank";
+ case GAL_ARITHMETIC_OP_WHERE: return "where";
+
+ case GAL_ARITHMETIC_OP_BITAND: return "bitand";
+ case GAL_ARITHMETIC_OP_BITOR: return "bitor";
+ case GAL_ARITHMETIC_OP_BITXOR: return "bitxor";
+ case GAL_ARITHMETIC_OP_BITLSH: return "lshift";
+ case GAL_ARITHMETIC_OP_BITRSH: return "rshift";
+ case GAL_ARITHMETIC_OP_BITNOT: return "bitnot";
+
+ case GAL_ARITHMETIC_OP_ABS: return "abs";
+ case GAL_ARITHMETIC_OP_POW: return "pow";
+ case GAL_ARITHMETIC_OP_SQRT: return "sqrt";
+ case GAL_ARITHMETIC_OP_LOG: return "log";
+ case GAL_ARITHMETIC_OP_LOG10: return "log10";
+
+ case GAL_ARITHMETIC_OP_MINVAL: return "minvalue";
+ case GAL_ARITHMETIC_OP_MAXVAL: return "maxvalue";
+ case GAL_ARITHMETIC_OP_NUMVAL: return "numvalue";
+ case GAL_ARITHMETIC_OP_SUMVAL: return "sumvalue";
+ case GAL_ARITHMETIC_OP_MEANVAL: return "meanvalue";
+ case GAL_ARITHMETIC_OP_STDVAL: return "stdvalue";
+ case GAL_ARITHMETIC_OP_MEDIANVAL: return "medianvalue";
+
+ case GAL_ARITHMETIC_OP_MIN: return "min";
+ case GAL_ARITHMETIC_OP_MAX: return "max";
+ case GAL_ARITHMETIC_OP_NUM: return "num";
+ case GAL_ARITHMETIC_OP_SUM: return "sum";
+ case GAL_ARITHMETIC_OP_MEAN: return "mean";
+ case GAL_ARITHMETIC_OP_STD: return "std";
+ case GAL_ARITHMETIC_OP_MEDIAN: return "median";
+
+ case GAL_ARITHMETIC_OP_TO_UINT8: return "uchar";
+ case GAL_ARITHMETIC_OP_TO_INT8: return "char";
+ case GAL_ARITHMETIC_OP_TO_UINT16: return "ushort";
+ case GAL_ARITHMETIC_OP_TO_INT16: return "short";
+ case GAL_ARITHMETIC_OP_TO_UINT32: return "uint";
+ case GAL_ARITHMETIC_OP_TO_INT32: return "int";
+ case GAL_ARITHMETIC_OP_TO_UINT64: return "ulong";
+ case GAL_ARITHMETIC_OP_TO_INT64: return "long";
+ case GAL_ARITHMETIC_OP_TO_FLOAT32: return "float32";
+ case GAL_ARITHMETIC_OP_TO_FLOAT64: return "float64";
default:
error(EXIT_FAILURE, 0, "%s: operator code %d not recognized",
@@ -1412,7 +1412,7 @@ gal_arithmetic(int operator, int flags, ...)
/* Prepare the variable arguments (starting after the flags argument). */
va_start(va, flags);
- /* Depending on the operator do the job: */
+ /* Depending on the operator, do the job: */
switch(operator)
{
@@ -1474,13 +1474,12 @@ gal_arithmetic(int operator, int flags, ...)
out=arithmetic_from_statistics(operator, flags, d1);
break;
- /* Absolute operator */
+ /* Absolute operator. */
case GAL_ARITHMETIC_OP_ABS:
d1 = va_arg(va, gal_data_t *);
out=arithmetic_abs(flags, d1);
break;
-
/* Multi-operand operators */
case GAL_ARITHMETIC_OP_MIN:
case GAL_ARITHMETIC_OP_MAX:
diff --git a/lib/dimension.c b/lib/dimension.c
index 3d8d8e2..ee76413 100644
--- a/lib/dimension.c
+++ b/lib/dimension.c
@@ -28,6 +28,7 @@ along with Gnuastro. If not, see
<http://www.gnu.org/licenses/>.
#include <error.h>
#include <stdlib.h>
+#include <gnuastro/wcs.h>
#include <gnuastro/pointer.h>
#include <gnuastro/dimension.h>
@@ -265,3 +266,427 @@ gal_dimension_dist_manhattan(size_t *a, size_t *b, size_t
ndim)
for(i=0;i<ndim;++i) out += (a[i] > b[i]) ? (a[i]-b[i]) : (b[i]-a[i]);
return out;
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/************************************************************************/
+/******************** Collapsing a dimension **********************/
+/************************************************************************/
+enum dimension_collapse_operation
+{
+ DIMENSION_COLLAPSE_INVALID, /* ==0 by C standard. */
+
+ DIMENSION_COLLAPSE_SUM,
+ DIMENSION_COLLAPSE_MEAN,
+ DIMENSION_COLLAPSE_NUMBER,
+};
+
+
+
+
+
+static gal_data_t *
+dimension_collapse_sanity_check(gal_data_t *in, gal_data_t *weight,
+ size_t c_dim, int hasblank, size_t *cnum,
+ double **warr)
+{
+ gal_data_t *wht=NULL;
+
+ /* The requested dimension to collapse cannot be larger than the input's
+ number of dimensions. */
+ if( c_dim > (in->ndim-1) )
+ error(EXIT_FAILURE, 0, "%s: the input has %zu dimensions, but you have "
+ "asked to collapse dimension %zu", __func__, in->ndim, c_dim);
+
+ /* If there is no blank value, there is no point in calculating the
+ number of points in each collapsed dataset (when necessary). In that
+ case, `cnum!=0'. */
+ if(hasblank==0)
+ *cnum=in->dsize[c_dim];
+
+ /* Weight sanity checks */
+ if(weight)
+ {
+ if( weight->ndim!=1 )
+ error(EXIT_FAILURE, 0, "%s: the weight dataset has %zu dimensions, "
+ "it must be one-dimensional", __func__, weight->ndim);
+ if( in->dsize[c_dim]!=weight->size )
+ error(EXIT_FAILURE, 0, "%s: the weight dataset has %zu elements, "
+ "but the input dataset has %zu elements in dimension %zu",
+ __func__, weight->size, in->dsize[c_dim], c_dim);
+ wht = ( weight->type == GAL_TYPE_FLOAT64
+ ? weight
+ : gal_data_copy_to_new_type(weight, GAL_TYPE_FLOAT64) );
+ *warr = wht->array;
+ }
+
+ /* Return the weight data structure. */
+ return wht;
+}
+
+
+
+
+/* Set the collapsed output sizes. */
+static void
+dimension_collapse_sizes(gal_data_t *in, size_t c_dim, size_t *outndim,
+ size_t *outdsize)
+{
+ size_t i, a=0;
+
+ if(in->ndim==1)
+ *outndim=outdsize[0]=1;
+ else
+ {
+ *outndim=in->ndim-1;
+ for(i=0;i<in->ndim;++i)
+ if(i!=c_dim) outdsize[a++]=in->dsize[i];
+ }
+}
+
+
+
+
+
+/* Depending on the operator, write the result into the output. */
+#define COLLAPSE_WRITE(OIND,IIND) { \
+ /* We need the sum when number operator is requested. */ \
+ if(farr) farr[ OIND ] += (warr ? warr[w] : 1) * inarr[ IIND ]; \
+ \
+ /* We don't need the number when the sum operator is requested. */ \
+ if(iarr) \
+ { \
+ if(num->type==GAL_TYPE_UINT8) iarr[ OIND ] = 1; \
+ else ++iarr[ OIND ]; \
+ } \
+ \
+ /* If the sum of weights for is needed, add it. */ \
+ if(wsumarr) wsumarr[ OIND ] += warr[w]; \
+ }
+
+
+
+/* Deal properly with blanks. */
+#define COLLAPSE_CHECKBLANK(OIND,IIND) { \
+ if(hasblank) \
+ { \
+ if(B==B) /* An integer type: blank can be checked with `=='. */ \
+ { \
+ if( inarr[IIND] != B ) COLLAPSE_WRITE(OIND,IIND); \
+ } \
+ else /* A floating point type where NAN != NAN. */ \
+ { \
+ if( inarr[IIND] == inarr[IIND] ) COLLAPSE_WRITE(OIND,IIND); \
+ } \
+ } \
+ else COLLAPSE_WRITE(OIND,IIND); \
+ }
+
+
+
+#define COLLAPSE_DIM(IT) { \
+ IT B, *inarr=in->array; \
+ if(hasblank) gal_blank_write(&B, in->type); \
+ switch(in->ndim) \
+ { \
+ /* 1D input dataset. */ \
+ case 1: \
+ for(i=0;i<in->dsize[0];++i) \
+ { \
+ if(weight) w=i; \
+ COLLAPSE_CHECKBLANK(0,i); \
+ } \
+ break; \
+ \
+ /* 2D input dataset. */ \
+ case 2: \
+ for(i=0;i<in->dsize[0];++i) \
+ for(j=0;j<in->dsize[1];++j) \
+ { \
+ /* In a more easy to understand format: \
+ dim==0 --> a=j; \
+ dim==1 --> a=i; */ \
+ a = c_dim==0 ? j : i; \
+ if(weight) w = c_dim == 0 ? i : j; \
+ COLLAPSE_CHECKBLANK(a, i*in->dsize[1] + j); \
+ } \
+ break; \
+ \
+ /* 3D input dataset. */ \
+ case 3: \
+ slice=in->dsize[1]*in->dsize[2]; \
+ for(i=0;i<in->dsize[0];++i) \
+ for(j=0;j<in->dsize[1];++j) \
+ for(k=0;k<in->dsize[2];++k) \
+ { \
+ /* In a more easy to understand format: \
+ dim==0 --> a=j; b=k; \
+ dim==1 --> a=i; b=k; \
+ dim==2 --> a=i; b=j; */ \
+ a = c_dim==0 ? j : i; \
+ b = c_dim==2 ? j : k; \
+ if(weight) w = c_dim==0 ? i : (c_dim==1 ? j : k); \
+ COLLAPSE_CHECKBLANK(a*outdsize[1]+b, \
+ i*slice + j*in->dsize[2] + k); \
+ } \
+ break; \
+ \
+ /* Input dataset's dimensionality not yet supported. */ \
+ default: \
+ error(EXIT_FAILURE, 0, "%s: %zu-dimensional datasets not yet " \
+ "supported, please contact us at %s to add this feature", \
+ __func__, in->ndim, PACKAGE_BUGREPORT); \
+ } \
+ }
+
+
+
+
+
+gal_data_t *
+gal_dimension_collapse_sum(gal_data_t *in, size_t c_dim, gal_data_t *weight)
+{
+ double *wsumarr=NULL;
+ int8_t *ii, *iarr=NULL;
+ size_t a, b, i, j, k, w, cnum=0;
+ size_t outdsize[10], slice, outndim;
+ int hasblank=gal_blank_present(in, 0);
+ double *dd, *df, *warr=NULL, *farr=NULL;
+ gal_data_t *wht=NULL, *sum=NULL, *num=NULL;
+
+ /* Basic sanity checks. */
+ wht=dimension_collapse_sanity_check(in, weight, c_dim, hasblank,
+ &cnum, &warr);
+
+ /* Set the size of the collapsed output. */
+ dimension_collapse_sizes(in, c_dim, &outndim, outdsize);
+
+ /* Allocate the sum (output) dataset. */
+ sum=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, outndim, outdsize, in->wcs,
+ 1, in->minmapsize, NULL, NULL, NULL);
+
+ /* The number dataset (when there are blank values).*/
+ if(hasblank)
+ num=gal_data_alloc(NULL, GAL_TYPE_INT8, outndim, outdsize, NULL,
+ 1, in->minmapsize, NULL, NULL, NULL);
+
+ /* Set the array pointers. */
+ if(sum) farr=sum->array;
+ if(num) iarr=num->array;
+
+ /* Parse the dataset. */
+ switch(in->type)
+ {
+ case GAL_TYPE_UINT8: COLLAPSE_DIM( uint8_t ); break;
+ case GAL_TYPE_INT8: COLLAPSE_DIM( int8_t ); break;
+ case GAL_TYPE_UINT16: COLLAPSE_DIM( uint16_t ); break;
+ case GAL_TYPE_INT16: COLLAPSE_DIM( int16_t ); break;
+ case GAL_TYPE_UINT32: COLLAPSE_DIM( uint32_t ); break;
+ case GAL_TYPE_INT32: COLLAPSE_DIM( int32_t ); break;
+ case GAL_TYPE_UINT64: COLLAPSE_DIM( uint64_t ); break;
+ case GAL_TYPE_INT64: COLLAPSE_DIM( int64_t ); break;
+ case GAL_TYPE_FLOAT32: COLLAPSE_DIM( float ); break;
+ case GAL_TYPE_FLOAT64: COLLAPSE_DIM( double ); break;
+ default:
+ error(EXIT_FAILURE, 0, "%s: type value (%d) not recognized",
+ __func__, in->type);
+ }
+
+ /* If `num' is zero on any element, set its sum to NaN. */
+ if(num)
+ {
+ ii = num->array;
+ df = (dd=sum->array) + sum->size;
+ do if(*ii++==0) *dd=NAN; while(++dd<df);
+ }
+
+ /* Remove the respective dimension in the WCS structure also (if any
+ exists). Note that `sum->ndim' has already been changed. So we'll use
+ `in->wcs'. */
+ gal_wcs_remove_dimension(sum->wcs, in->ndim-c_dim);
+
+ /* Clean up and return. */
+ if(wht!=weight) gal_data_free(wht);
+ if(num) gal_data_free(num);
+ return sum;
+}
+
+
+
+
+
+gal_data_t *
+gal_dimension_collapse_mean(gal_data_t *in, size_t c_dim,
+ gal_data_t *weight)
+{
+ double wsum=NAN;
+ double *wsumarr=NULL;
+ int8_t *ii, *iarr=NULL;
+ size_t outdsize[10], slice, outndim;
+ int hasblank=gal_blank_present(in, 0);
+ size_t a, b, i, j, k, w, cnum=0;
+ gal_data_t *wht=NULL, *sum=NULL, *num=NULL;
+ double *dd, *dw, *df, *warr=NULL, *farr=NULL;
+
+ /* Basic sanity checks. */
+ wht=dimension_collapse_sanity_check(in, weight, c_dim, hasblank,
+ &cnum, &warr);
+
+ /* Set the size of the collapsed output. */
+ dimension_collapse_sizes(in, c_dim, &outndim, outdsize);
+
+ /* The sum array. */
+ sum=gal_data_alloc(NULL, GAL_TYPE_FLOAT64, outndim, outdsize, in->wcs,
+ 1, in->minmapsize, NULL, NULL, NULL);
+
+ /* If a weighted mean is requested. */
+ if( weight )
+ {
+ /* There are blank values, so we'll need to keep the sums of the
+ weights for each collapsed dimension */
+ if( hasblank )
+ wsumarr=gal_pointer_allocate(GAL_TYPE_FLOAT64, sum->size, 1,
+ __func__, "wsumarr");
+
+ /* There aren't any blank values, so one summation over the
+ weights is enough to calculate the weighted mean. */
+ else
+ {
+ wsum=0.0f;
+ df=(dd=weight->array)+weight->size;
+ do wsum += *dd++; while(dd<df);
+ }
+ }
+ /* No weight is given, so we'll need the number of elements. */
+ else if( hasblank )
+ num=gal_data_alloc(NULL, GAL_TYPE_INT32, outndim, outdsize, NULL,
+ 1, in->minmapsize, NULL, NULL, NULL);
+
+ /* Set the array pointers. */
+ if(sum) farr=sum->array;
+ if(num) iarr=num->array;
+
+ /* Parse the dataset. */
+ switch(in->type)
+ {
+ case GAL_TYPE_UINT8: COLLAPSE_DIM( uint8_t ); break;
+ case GAL_TYPE_INT8: COLLAPSE_DIM( int8_t ); break;
+ case GAL_TYPE_UINT16: COLLAPSE_DIM( uint16_t ); break;
+ case GAL_TYPE_INT16: COLLAPSE_DIM( int16_t ); break;
+ case GAL_TYPE_UINT32: COLLAPSE_DIM( uint32_t ); break;
+ case GAL_TYPE_INT32: COLLAPSE_DIM( int32_t ); break;
+ case GAL_TYPE_UINT64: COLLAPSE_DIM( uint64_t ); break;
+ case GAL_TYPE_INT64: COLLAPSE_DIM( int64_t ); break;
+ case GAL_TYPE_FLOAT32: COLLAPSE_DIM( float ); break;
+ case GAL_TYPE_FLOAT64: COLLAPSE_DIM( double ); break;
+ default:
+ error(EXIT_FAILURE, 0, "%s: type value (%d) not recognized",
+ __func__, in->type);
+ }
+
+ /* If `num' is zero on any element, set its sum to NaN. */
+ if(num)
+ {
+ ii = num->array;
+ df = (dd=sum->array) + sum->size;
+ do if(*ii++==0) *dd=NAN; while(++dd<df);
+ }
+
+ /* Divide the sum by the number. */
+ df = (dd=sum->array) + sum->size;
+ if(weight)
+ {
+ if(hasblank) { dw=wsumarr; do *dd /= *dw++; while(++dd<df); }
+ else do *dd /= wsum; while(++dd<df);
+ }
+ else
+ if(num) { ii = num->array; do *dd /= *ii++; while(++dd<df); }
+ else do *dd /= cnum; while(++dd<df);
+
+ /* Correct the WCS, clean up and return. */
+ gal_wcs_remove_dimension(sum->wcs, in->ndim-c_dim);
+ if(wht!=weight) gal_data_free(wht);
+ if(wsumarr) free(wsumarr);
+ gal_data_free(num);
+ return sum;
+}
+
+
+
+
+
+gal_data_t *
+gal_dimension_collapse_number(gal_data_t *in, size_t c_dim)
+{
+ double *wsumarr=NULL;
+ double *warr=NULL, *farr=NULL;
+ int32_t *ii, *iif, *iarr=NULL;
+ size_t a, b, i, j, k, w, cnum=0;
+ size_t outdsize[10], slice, outndim;
+ int hasblank=gal_blank_present(in, 0);
+ gal_data_t *weight=NULL, *wht=NULL, *num=NULL;
+
+ /* Basic sanity checks. */
+ wht=dimension_collapse_sanity_check(in, weight, c_dim, hasblank,
+ &cnum, &warr);
+
+ /* Set the size of the collapsed output. */
+ dimension_collapse_sizes(in, c_dim, &outndim, outdsize);
+
+ /* The number dataset (when there are blank values).*/
+ num=gal_data_alloc(NULL, GAL_TYPE_INT32, outndim, outdsize, in->wcs,
+ 1, in->minmapsize, NULL, NULL, NULL);
+
+ /* Set the array pointers. */
+ iarr=num->array;
+
+ /* Parse the input dataset (if necessary). */
+ if(hasblank)
+ switch(in->type)
+ {
+ case GAL_TYPE_UINT8: COLLAPSE_DIM( uint8_t ); break;
+ case GAL_TYPE_INT8: COLLAPSE_DIM( int8_t ); break;
+ case GAL_TYPE_UINT16: COLLAPSE_DIM( uint16_t ); break;
+ case GAL_TYPE_INT16: COLLAPSE_DIM( int16_t ); break;
+ case GAL_TYPE_UINT32: COLLAPSE_DIM( uint32_t ); break;
+ case GAL_TYPE_INT32: COLLAPSE_DIM( int32_t ); break;
+ case GAL_TYPE_UINT64: COLLAPSE_DIM( uint64_t ); break;
+ case GAL_TYPE_INT64: COLLAPSE_DIM( int64_t ); break;
+ case GAL_TYPE_FLOAT32: COLLAPSE_DIM( float ); break;
+ case GAL_TYPE_FLOAT64: COLLAPSE_DIM( double ); break;
+ default:
+ error(EXIT_FAILURE, 0, "%s: type value (%d) not recognized",
+ __func__, in->type);
+ }
+ else
+ {
+ iif=(ii=num->array)+num->size;
+ do *ii++ = cnum; while(ii<iif);
+ }
+
+ /* Remove the respective dimension in the WCS structure also (if any
+ exists). Note that `sum->ndim' has already been changed. So we'll use
+ `in->wcs'. */
+ gal_wcs_remove_dimension(num->wcs, in->ndim-c_dim);
+
+ /* Return. */
+ if(wht!=weight) gal_data_free(wht);
+ return num;
+}
diff --git a/lib/gnuastro/dimension.h b/lib/gnuastro/dimension.h
index 5c83a0d..a0623a2 100644
--- a/lib/gnuastro/dimension.h
+++ b/lib/gnuastro/dimension.h
@@ -97,6 +97,23 @@ gal_dimension_dist_manhattan(size_t *a, size_t *b, size_t
ndim);
/************************************************************************/
+/******************** Collapsing a dimension **********************/
+/************************************************************************/
+gal_data_t *
+gal_dimension_collapse_sum(gal_data_t *in, size_t c_dim, gal_data_t *weight);
+
+gal_data_t *
+gal_dimension_collapse_mean(gal_data_t *in, size_t c_dim,
+ gal_data_t *weight);
+
+gal_data_t *
+gal_dimension_collapse_number(gal_data_t *in, size_t c_dim);
+
+
+
+
+
+/************************************************************************/
/******************** Neighbors **********************/
/************************************************************************/
/* Purpose
diff --git a/lib/gnuastro/wcs.h b/lib/gnuastro/wcs.h
index 72be5a0..13c2bb5 100644
--- a/lib/gnuastro/wcs.h
+++ b/lib/gnuastro/wcs.h
@@ -74,6 +74,9 @@ struct wcsprm *
gal_wcs_copy(struct wcsprm *wcs);
void
+gal_wcs_remove_dimension(struct wcsprm *wcs, size_t fitsdim);
+
+void
gal_wcs_on_tile(gal_data_t *tile);
double *
diff --git a/lib/wcs.c b/lib/wcs.c
index c7d7376..3fe19cf 100644
--- a/lib/wcs.c
+++ b/lib/wcs.c
@@ -258,6 +258,176 @@ gal_wcs_copy(struct wcsprm *wcs)
+/* Remove the algorithm part of CTYPE (anything after, and including, a
+ `-') if necessary. */
+static void
+wcs_ctype_noalgorithm(char *str)
+{
+ size_t i, len=strlen(str);
+ for(i=0;i<len;++i) if(str[i]=='-') { str[i]='\0'; break; }
+}
+
+
+
+
+/* See if the CTYPE string ends with TAN. */
+static int
+wcs_ctype_has_tan(char *str)
+{
+ size_t len=strlen(str);
+
+ return !strcmp(&str[len-3], "TAN");
+}
+
+
+
+
+
+/* Remove dimension. */
+#define WCS_REMOVE_DIM_CHECK 0
+void
+gal_wcs_remove_dimension(struct wcsprm *wcs, size_t fitsdim)
+{
+ size_t c, i, j, naxis=wcs->naxis;
+
+ /* Sanity check. */
+ if(fitsdim==0 || fitsdim>wcs->naxis)
+ error(EXIT_FAILURE, 0, "%s: requested dimension (fitsdim=%zu) must be "
+ "larger than zero and smaller than the number of dimensions in "
+ "the given WCS structure (%zu)", __func__, fitsdim, naxis);
+
+ /* If the WCS structure is NULL, just return. */
+ if(wcs==NULL) return;
+
+ /**************************************************/
+#if WCS_REMOVE_DIM_CHECK
+ printf("\n\nfitsdim: %zu\n", fitsdim);
+ printf("\n##################\n");
+ /*
+ wcs->pc[0]=0; wcs->pc[1]=1; wcs->pc[2]=2;
+ wcs->pc[3]=3; wcs->pc[4]=4; wcs->pc[5]=5;
+ wcs->pc[6]=6; wcs->pc[7]=7; wcs->pc[8]=8;
+ */
+ for(i=0;i<wcs->naxis;++i)
+ {
+ for(j=0;j<wcs->naxis;++j)
+ printf("%-5g", wcs->pc[i*wcs->naxis+j]);
+ printf("\n");
+ }
+#endif
+ /**************************************************/
+
+
+ /* First loop over the arrays. */
+ for(i=0;i<naxis;++i)
+ {
+ /* The dimensions are in FITS order, but counting starts from 0, so
+ we'll have to subtract 1 from `fitsdim'. */
+ if(i>fitsdim-1)
+ {
+ /* 1-D arrays. */
+ if(wcs->crpix) wcs->crpix[i-1] = wcs->crpix[i];
+ if(wcs->cdelt) wcs->cdelt[i-1] = wcs->cdelt[i];
+ if(wcs->crval) wcs->crval[i-1] = wcs->crval[i];
+ if(wcs->crota) wcs->crota[i-1] = wcs->crota[i];
+ if(wcs->crder) wcs->crder[i-1] = wcs->crder[i];
+ if(wcs->csyer) wcs->csyer[i-1] = wcs->csyer[i];
+
+ /* The strings are all statically allocated, so we don't need to
+ check. */
+ memcpy(wcs->cunit[i-1], wcs->cunit[i], 72);
+ memcpy(wcs->ctype[i-1], wcs->ctype[i], 72);
+ memcpy(wcs->cname[i-1], wcs->cname[i], 72);
+
+ /* For 2-D arrays, just bring up all the rows. We'll fix the
+ columns in a second loop. */
+ for(j=0;j<naxis;++j)
+ {
+ if(wcs->pc) wcs->pc[ (i-1)*naxis+j ] = wcs->pc[ i*naxis+j ];
+ if(wcs->cd) wcs->cd[ (i-1)*naxis+j ] = wcs->cd[ i*naxis+j ];
+ }
+ }
+ }
+
+
+ /**************************************************/
+#if WCS_REMOVE_DIM_CHECK
+ printf("\n###### Respective row removed (replaced).\n");
+ for(i=0;i<wcs->naxis;++i)
+ {
+ for(j=0;j<wcs->naxis;++j)
+ printf("%-5g", wcs->pc[i*wcs->naxis+j]);
+ printf("\n");
+ }
+#endif
+ /**************************************************/
+
+
+ /* Second loop for 2D arrays. */
+ c=0;
+ for(i=0;i<naxis;++i)
+ for(j=0;j<naxis;++j)
+ if(j!=fitsdim-1)
+ {
+ if(wcs->pc) wcs->pc[ c ] = wcs->pc[ i*naxis+j ];
+ if(wcs->cd) wcs->cd[ c ] = wcs->cd[ i*naxis+j ];
+ ++c;
+ }
+
+
+ /* Correct the total number of dimensions in the WCS structure. */
+ naxis = wcs->naxis -= 1;
+
+
+ /* The `TAN' algorithm needs two dimensions. So we need to remove it when
+ it can cause confusion. */
+ switch(naxis)
+ {
+ /* The `TAN' algorithm cannot be used for any single-dimensional
+ dataset. So we'll have to remove it if it exists. */
+ case 1:
+ wcs_ctype_noalgorithm(wcs->ctype[0]);
+ break;
+
+ /* For any other dimensionality, `TAN' should be kept only when exactly
+ two dimensions have it. */
+ default:
+
+ c=0;
+ for(i=0;i<naxis;++i)
+ if( wcs_ctype_has_tan(wcs->ctype[i]) )
+ ++c;
+
+ if(c!=2)
+ for(i=0;i<naxis;++i)
+ if( wcs_ctype_has_tan(wcs->ctype[i]) )
+ wcs_ctype_noalgorithm(wcs->ctype[i]);
+ break;
+ }
+
+
+
+ /**************************************************/
+#if WCS_REMOVE_DIM_CHECK
+ printf("\n###### Respective column removed.\n");
+ for(i=0;i<naxis;++i)
+ {
+ for(j=0;j<naxis;++j)
+ printf("%-5g", wcs->pc[i*naxis+j]);
+ printf("\n");
+ }
+ printf("\n###### One final string\n");
+ for(i=0;i<naxis;++i)
+ printf("%s\n", wcs->ctype[i]);
+ exit(0);
+#endif
+ /**************************************************/
+}
+
+
+
+
+
/* Using the block data structure of the tile, add a WCS structure for
it. In many cases, tiles are created for internal processing, so there
is no need to keep their WCS. Hence for preformance reasons, when