gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 75ba49e: Tile and Arithmetic libraries documen


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 75ba49e: Tile and Arithmetic libraries documented in manual
Date: Wed, 3 May 2017 00:57:48 -0400 (EDT)

branch: master
commit 75ba49ed10b30262cde6d3e132deb39df9908d4d
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Tile and Arithmetic libraries documented in manual
    
    The `tile.h' and `arithmetic.h' headers are now fully documented in the
    manual. In the process, the following changes were also made:
    
     - The operator argument to `GAL_TILE_PARSE_OPERATE' was moved to its end,
       similar to the `GAL_DIMENSION_NEIGHBOR_OP' function-like macro. It is
       much more convenient (and readable) if the expression-block is at the
       end so it can take its own line and with the finishing of the block the
       full macro actually finishes.
    
     - The internally necessary `gal_arithmetic_*' functions in `arithmetic.h'
       were moved to a new `arithmetic-internal.h' header.
    
     - BuildProgram was added to the README and also the generation of `Man'
       pages. Its description was also updated in its `ui.c'.
    
     - MakeCatalog will now complain with an error if the object label image
       doesn't have any non-zero pixels.
    
     - If a clump image was provided, but contained no clumps, MakeCatalog will
       now behave as if no clumps image was provided.
---
 README                                      |   6 +
 bin/buildprog/ui.c                          |   6 +-
 bin/mkcatalog/ui.c                          |  38 +-
 bin/noisechisel/clumps.c                    |  13 +-
 bin/noisechisel/detection.c                 |   2 +-
 bin/noisechisel/sky.c                       |  21 +-
 bin/noisechisel/threshold.c                 |   8 +-
 bin/noisechisel/ui.c                        |  15 +-
 doc/Makefile.am                             |  17 +-
 doc/gnuastro.texi                           | 963 +++++++++++++++++++++++++---
 lib/Makefile.am                             |  12 +-
 lib/arithmetic-binary.c                     |   1 +
 lib/arithmetic-onlyint.c                    |   1 +
 lib/arithmetic.c                            |   4 +-
 lib/binary.c                                |  12 +-
 lib/blank.c                                 |   2 +-
 lib/gnuastro-internal/arithmetic-internal.h |  74 +++
 lib/gnuastro/arithmetic.h                   |  22 +-
 lib/gnuastro/tile.h                         | 260 +++-----
 lib/statistics.c                            |  21 +-
 lib/tile.c                                  | 161 ++---
 21 files changed, 1209 insertions(+), 450 deletions(-)

diff --git a/README b/README
index 5f0e85e..7f8d3b7 100644
--- a/README
+++ b/README
@@ -37,6 +37,12 @@ context under categories/chapters.
     and growing set of arithmetic, mathematical, and even statistical
     operators (for example +, -, *, /, sqrt, log, min, average, median).
 
+  - BuildProgram (astbuildprog) Compile, link and run programs that depend
+    on the Gnuastro library. BuildProgram will automatically link with the
+    libraries that Gnuastro depends on, so there is no need to explicily
+    mention them every time you are compiling a Gnuastro library dependent
+    program.
+
   - ConvertType (astconvertt): Convert astronomical data files (FITS or
     IMH) to and from several other standard image and data formats, for
     example TXT, JPEG, EPS or PDF.
diff --git a/bin/buildprog/ui.c b/bin/buildprog/ui.c
index b949b27..1814dc0 100644
--- a/bin/buildprog/ui.c
+++ b/bin/buildprog/ui.c
@@ -65,8 +65,10 @@ doc[] = GAL_STRINGS_TOP_HELP_INFO PROGRAM_NAME" will compile 
and run a "
   "depends on. Hence you do not have to worry about explicitly linking "
   "with CFITSIO for example if you want to work on a FITS file, or with "
   "GSL if you want to use GNU Scientific Library's functions. You can "
-  "optionally use the compiler `-I' and `-L' options to use other "
-  "include headers or link with other libraries respectively.\n"
+  "optionally use the standard compiler options `-I', `-L', and `-l'. "
+  "You can use these to specify non-standard directories to look for "
+  "headers, directories to look for compiled libraries, or libraries to "
+  "link with, respectively.\n"
   GAL_STRINGS_MORE_HELP_INFO
   /* After the list of options: */
   "\v"
diff --git a/bin/mkcatalog/ui.c b/bin/mkcatalog/ui.c
index ee64156..e6db9ff 100644
--- a/bin/mkcatalog/ui.c
+++ b/bin/mkcatalog/ui.c
@@ -575,6 +575,14 @@ ui_preparations_read_keywords(struct mkcatalogparams *p)
     }
 
 
+  /* If there were no objects in the input, then inform the user with an
+     error (no catalog was built). */
+  if(p->numobjects==0)
+    error(EXIT_FAILURE, 0, "no object labels (non-zero pixels) in "
+          "%s (hdu %s). To make a catalog, labeled regions must be defined",
+          objectsfile, p->objectshdu);
+
+
   /* Read the keywords from the clumps image if necessary. */
   if(p->clumps)
     {
@@ -589,6 +597,16 @@ ui_preparations_read_keywords(struct mkcatalogparams *p)
     }
 
 
+  /* If there were no clumps, then free the clumps array and set it to
+     NULL, so for the rest of the processing, MakeCatalog things that no
+     clumps image was given. */
+  if(p->numclumps==0)
+    {
+      gal_data_free(p->clumps);
+      p->clumps=NULL;
+    }
+
+
   /* Clean up. */
   keys[0].name=keys[1].name=NULL;
   keys[0].array=keys[1].array=NULL;
@@ -705,14 +723,18 @@ ui_preparations_outnames(struct mkcatalogparams *p)
          `tableformat' option. */
       gal_tableintern_check_fits_format(p->cp.output, p->cp.tableformat);
 
-      /* If a clumps image has been read, we have two outputs. */
-      if(p->clumps)  ui_preparations_both_names(p, p->cp.output);
-      else           p->objectsout=p->cp.output;
+      /* If a clumps image has been read (and there are any clumps in the
+         image), then we have two outputs. */
+      if(p->clumps)
+        ui_preparations_both_names(p, p->cp.output);
+      else
+        p->objectsout=p->cp.output;
     }
   else
     {
       /* Both clumps and object catalogs are necessary. */
-      if(p->clumps)  ui_preparations_both_names(p, p->inputname);
+      if(p->clumps)
+        ui_preparations_both_names(p, p->inputname);
 
       /* We only need one objects catalog. */
       else
@@ -784,15 +806,15 @@ ui_preparations(struct mkcatalogparams *p)
   ui_preparations_read_inputs(p);
 
 
-  /* Set the output filename(s). */
-  ui_preparations_outnames(p);
-
-
   /* Read the helper keywords from the inputs and if they aren't present
      then calculate the necessary parameters. */
   ui_preparations_read_keywords(p);
 
 
+  /* Set the output filename(s). */
+  ui_preparations_outnames(p);
+
+
   /* Allocate the output columns to fill up with the program. */
   columns_define_alloc(p);
 
diff --git a/bin/noisechisel/clumps.c b/bin/noisechisel/clumps.c
index 6f81a3b..20f9414 100644
--- a/bin/noisechisel/clumps.c
+++ b/bin/noisechisel/clumps.c
@@ -965,8 +965,8 @@ clumps_correct_sky_labels_for_check(struct 
clumps_thread_params *cltprm,
 
 
   /* Go over this tile and correct the values. */
-  GAL_TILE_PARSE_OPERATE({if(*i>0) *i=ninds[ *(int32_t *)i ];},
-                         tile, NULL, 0, 1);
+  GAL_TILE_PARSE_OPERATE( tile, NULL, 0, 1,
+                          {if(*i>0) *i=ninds[ *(int32_t *)i ];} );
 
   /* Clean up. */
   gal_data_free(newinds);
@@ -1066,7 +1066,7 @@ clumps_find_make_sn_table(void *in_prm)
              used. */
           c=0;
           indarr=cltprm.indexs->array;
-          GAL_TILE_PO_OISET(int32_t, int, {
+          GAL_TILE_PO_OISET(int32_t, int, tile, NULL, 0, 1, {
               /* This pixel's index over all the image. */
               ind = (int32_t *)i - (int32_t *)(p->clabel->array);
               gal_dimension_index_to_coord(ind, ndim, dsize, icoord);
@@ -1106,7 +1106,7 @@ clumps_find_make_sn_table(void *in_prm)
                       }
                   */
                 }
-            }, tile, NULL, 0, 1);
+            });
 
           /* Correct the number of indexs. */
           cltprm.indexs->size=cltprm.indexs->dsize[0]=c;
@@ -1116,9 +1116,8 @@ clumps_find_make_sn_table(void *in_prm)
 
           /* Set all river pixels to CLUMPS_INIT (to be distinguishable
              from the detected regions). */
-          GAL_TILE_PO_OISET(int32_t, int,
-                            {if(*i==CLUMPS_RIVER) *i=CLUMPS_INIT;},
-                            tile, NULL, 0, 1);
+          GAL_TILE_PO_OISET( int32_t, int, tile, NULL, 0, 1,
+                             {if(*i==CLUMPS_RIVER) *i=CLUMPS_INIT;} );
 
           /* For a check, the step variable will be set. */
           if(clprm->step==1)
diff --git a/bin/noisechisel/detection.c b/bin/noisechisel/detection.c
index f528927..417b158 100644
--- a/bin/noisechisel/detection.c
+++ b/bin/noisechisel/detection.c
@@ -182,7 +182,7 @@ static void
 detection_write_in_large(gal_data_t *tile, gal_data_t *copy)
 {
   uint8_t *c=copy->array;
-  GAL_TILE_PARSE_OPERATE({*i=*c++;}, tile, NULL, 0, 0);
+  GAL_TILE_PARSE_OPERATE(tile, NULL, 0, 0, {*i=*c++;});
 }
 
 
diff --git a/bin/noisechisel/sky.c b/bin/noisechisel/sky.c
index 92ee414..7f369e4 100644
--- a/bin/noisechisel/sky.c
+++ b/bin/noisechisel/sky.c
@@ -89,7 +89,7 @@ sky_mean_std_undetected(void *in_prm)
       bintile->size=tile->size;
       bintile->dsize=tile->dsize;
       bintile->array=gal_tile_block_relative_to_other(tile, p->binary);
-      GAL_TILE_PARSE_OPERATE({if(!*o) numsky++;}, tile, bintile, 1, 1);
+      GAL_TILE_PARSE_OPERATE(tile, bintile, 1, 1, {if(!*o) numsky++;});
 
       /* Only continue, if the fraction of Sky values are less than the
          requested fraction. */
@@ -97,14 +97,13 @@ sky_mean_std_undetected(void *in_prm)
         {
           /* Calculate the mean and STD over this tile. */
           s=s2=0.0f;
-          GAL_TILE_PARSE_OPERATE(
-                                 {
-                                   if(!*o)
-                                     {
-                                       s  += *i;
-                                       s2 += *i * *i;
-                                     }
-                                 }, tile, bintile, 1, 1);
+          GAL_TILE_PARSE_OPERATE(tile, bintile, 1, 1, {
+              if(!*o)
+                {
+                  s  += *i;
+                  s2 += *i * *i;
+                }
+            } );
           darr[0]=s/numsky;
           darr[1]=sqrt( (s2-s*s/numsky)/numsky );
 
@@ -251,7 +250,7 @@ sky_subtract(struct noisechiselparams *p)
       tile=&p->cp.tl.tiles[tid];
 
       /* First subtract the Sky value from the input image. */
-      GAL_TILE_PARSE_OPERATE({*i-=sky[tid];}, tile, NULL, 0, 0);
+      GAL_TILE_PARSE_OPERATE(tile, NULL, 0, 0, {*i-=sky[tid];});
 
       /* Change to the convolved image. */
       tarray=tile->array;
@@ -268,7 +267,7 @@ sky_subtract(struct noisechiselparams *p)
          the threshold have to be checked for a NaN which are by
          definition a very small fraction of the total pixels. And if
          there are NaN pixels in the image. */
-      GAL_TILE_PARSE_OPERATE({*i-=sky[tid];}, tile, NULL, 0, 0);
+      GAL_TILE_PARSE_OPERATE(tile, NULL, 0, 0, {*i-=sky[tid];});
 
       /* Revert back to the original block. */
       tile->array=tarray;
diff --git a/bin/noisechisel/threshold.c b/bin/noisechisel/threshold.c
index a555164..55bc66c 100644
--- a/bin/noisechisel/threshold.c
+++ b/bin/noisechisel/threshold.c
@@ -110,12 +110,12 @@ threshold_apply_on_thread(void *in_prm)
              will help in efficiency, because the compiler can move this
              check out of the loop and only check for NaN values when we
              know the tile has blank pixels. */
-          GAL_TILE_PO_OISET(float, uint8_t, {
+          GAL_TILE_PO_OISET(float, uint8_t, tile, p->binary, 1, 0, {
               *o = ( *i > value1[tid]
                      ? ( *i > value2[tid] ? THRESHOLD_NO_ERODE_VALUE : 1 )
                      : ( (tile->flag & GAL_DATA_FLAG_HASBLANK) && !(*i==*i)
                          ? GAL_BLANK_UINT8 : 0 ) );
-            }, tile, p->binary, 1, 0);
+            });
 
           /* Revert the tile's pointers back to what they were. */
           if(p->conv) { tile->array=tarray; tile->block=tblock; }
@@ -127,12 +127,12 @@ threshold_apply_on_thread(void *in_prm)
 
           /* See the explanation above the same step in the quantile
              threshold for an explanation. */
-          GAL_TILE_PO_OISET(float, uint8_t, {
+          GAL_TILE_PO_OISET(float, uint8_t, tile, p->binary, 1, 0, {
               *o = ( ( *i - value1[tid] > p->dthresh * value2[tid] )
                      ? 1
                      : ( (tile->flag & GAL_DATA_FLAG_HASBLANK) && !(*i==*i)
                          ? GAL_BLANK_UINT8 : 0 ) );
-            }, tile, p->binary, 1, 0);
+            });
           break;
 
 
diff --git a/bin/noisechisel/ui.c b/bin/noisechisel/ui.c
index 2db2aa8..7848a8e 100644
--- a/bin/noisechisel/ui.c
+++ b/bin/noisechisel/ui.c
@@ -474,7 +474,7 @@ ui_prepare_kernel(struct noisechiselparams *p)
 static void
 ui_prepare_tiles(struct noisechiselparams *p)
 {
-  gal_data_t *check, *tile;
+  gal_data_t *check;
   struct gal_tile_two_layer_params *tl=&p->cp.tl, *ltl=&p->ltl;
 
 
@@ -512,18 +512,13 @@ ui_prepare_tiles(struct noisechiselparams *p)
       }
 
 
-  /* If the input has blank elements, then go over all the tiles and set
-     their blank flag to 1 if they have blank values within
-     them. Afterwards, set the use-zero flag for the tiles in any case.*/
+  /* If the input has blank elements, then set teh appropriate flag for
+     each tile.*/
   if( p->input->flag & GAL_DATA_FLAG_HASBLANK )
     {
-      gal_tile_full_blank_flag(tl->tiles,  p->cp.numthreads);
-      gal_tile_full_blank_flag(ltl->tiles, p->cp.numthreads);
+      gal_tile_block_blank_flag(tl->tiles,  p->cp.numthreads);
+      gal_tile_block_blank_flag(ltl->tiles, p->cp.numthreads);
     }
-  for(tile=tl->tiles;tile!=NULL;tile=tile->next)
-    tile->flag |= GAL_DATA_FLAG_BLANK_CH;
-  for(tile=ltl->tiles;tile!=NULL;tile=tile->next)
-    tile->flag |= GAL_DATA_FLAG_BLANK_CH;
 
 
   /* Make the tile check image if requested. */
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 90f54fb..ff81d4f 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -84,6 +84,9 @@ dist_infognuastro_DATA = $(top_srcdir)/doc/gnuastro-figures/*
 if COND_ARITHMETIC
   MAYBE_ARITHMETIC_MAN = man/astarithmetic.1
 endif
+if COND_BUILDPROG
+  MAYBE_BUILDPROG_MAN = man/astbuildprog.1
+endif
 if COND_CONVERTT
   MAYBE_CONVERTT_MAN = man/astconvertt.1
 endif
@@ -123,11 +126,11 @@ endif
 #if COND_TEMPLATE
 #  MAYBE_TEMPLATE_MAN = man/astTEMPLATE.1
 #endif
-dist_man_MANS = $(MAYBE_ARITHMETIC_MAN) $(MAYBE_CONVERTT_MAN)          \
-  $(MAYBE_CONVOLVE_MAN) $(MAYBE_COSMICCAL_MAN) $(MAYBE_CROP_MAN)       \
-  $(MAYBE_FITS_MAN) $(MAYBE_WARP_MAN) $(MAYBE_MKCATALOG_MAN)           \
-  $(MAYBE_MKNOISE_MAN) $(MAYBE_MKPROF_MAN) $(MAYBE_NOISECHISEL_MAN)    \
-  $(MAYBE_STATISTICS_MAN) $(MAYBE_TABLE_MAN)
+dist_man_MANS = $(MAYBE_ARITHMETIC_MAN) $(MAYBE_BUILDPROG_MAN)          \
+  $(MAYBE_CONVERTT_MAN) $(MAYBE_CONVOLVE_MAN) $(MAYBE_COSMICCAL_MAN)    \
+  $(MAYBE_CROP_MAN) $(MAYBE_FITS_MAN) $(MAYBE_WARP_MAN)                 \
+  $(MAYBE_MKCATALOG_MAN) $(MAYBE_MKNOISE_MAN) $(MAYBE_MKPROF_MAN)       \
+  $(MAYBE_NOISECHISEL_MAN) $(MAYBE_STATISTICS_MAN) $(MAYBE_TABLE_MAN)
 
 
 ## See if help2man is present or not. When help2man doesn't exist, we don't
@@ -149,6 +152,10 @@ man/astarithmetic.1: $(top_srcdir)/bin/arithmetic/args.h  
$(ALLMANSDEP)
        $(MAYBE_HELP2MAN) -n "arithmetic operations on images and numbers" \
                          --libtool $(toputildir)/arithmetic/astarithmetic
 
+man/astbuildprog.1: $(top_srcdir)/bin/buildprog/args.h  $(ALLMANSDEP)
+       $(MAYBE_HELP2MAN) -n "compile, link with Gnuastro library and its 
dependencies, and run a C program"      \
+                         --libtool $(toputildir)/convertt/astconvertt
+
 man/astconvertt.1: $(top_srcdir)/bin/convertt/args.h  $(ALLMANSDEP)
        $(MAYBE_HELP2MAN) -n "convert known data types to each other"      \
                          --libtool $(toputildir)/convertt/astconvertt
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 92fbe12..b34d510 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -518,7 +518,7 @@ CosmicCalculator
 Library
 
 * Review of library fundamentals::  Guide on libraries and linking.
-* BuildProgram::                Link and run source files using Gnuastro's 
library.
+* BuildProgram::                Link and run source files with this library.
 * Gnuastro library::            Description of all library functions.
 * Library demo programs::       Demonstration for using libraries.
 
@@ -535,7 +535,7 @@ BuildProgram
 Gnuastro library
 
 * Configuration information::   General information about library config.
-* Library data types::          Definitions and functions for types in 
Gnuastro.
+* Library data types::          Definitions and functions for types.
 * Library blank values::        Blank values and functions to deal with them.
 * Library data container::      General data container in Gnuastro.
 * Dimensions::                  Dealing with coordinates and dimensions.
@@ -574,13 +574,18 @@ Linked lists (@file{list.h})
 
 FITS files (@file{fits.h})
 
-* FITS macros errors filenames::  General macros, errors and checking FITS 
names
+* FITS macros errors filenames::  General macros, errors and checking names.
 * CFITSIO and Gnuastro types::  Conversion between FITS and Gnuastro types.
 * FITS HDUs::                   Opening and getting information about HDUs.
 * FITS header keywords::        Reading and writing FITS header keywords.
 * FITS arrays::                 Reading and writing FITS images/arrays.
 * FITS tables::                 Reading and writing FITS tables.
 
+Tessellation library (@file{tile.h})
+
+* Independent tiles::           Work on or check independent tiles.
+* Tile grid::                   Cover a full dataset with non-overlapping 
tiles.
+
 Multithreaded programming (@file{threads.h})
 
 * Implementation of pthread_barrier::  Some systems don't have pthread_barrier
@@ -8644,21 +8649,22 @@ condition. Three operands are required for 
@command{where}. The input
 format is demonstrated in this simplified example:
 
 @example
-$ astarithmetic modify.fits cond.fits if-true.fits where
+$ astarithmetic modify.fits binary.fits if-true.fits where
 @end example
 
-The value of any pixel in @file{out.fits} that corresponds to a non-zero
-pixel of @file{cond.fits} will be changed to the value of the same pixel in
address@hidden (or a fixed number). The third and second popped
-operands (@file{modify.fits} and @file{cond.fits} above, see @ref{Reverse
-polish notation}) have to have the same
+The value of any pixel in @file{modify.fits} that corresponds to a non-zero
+pixel of @file{binary.fits} will be changed to the value of the same pixel
+in @file{if-true.fits} (this may also be a number). The 3rd and 2nd popped
+operands (@file{modify.fits} and @file{binary.fits} respectively, see
address@hidden polish notation}) have to have the same
 dimensions/size. @file{if-true.fits} can be either a number, or have the
 same dimension/size as the other two.
 
-That @file{cond.fits} has to have @code{uint8} (or @code{unsigned char} in
-standard C) type (see @ref{Numeric data types} and the type conversion
-operators below). However, ommonly this is no problem because in most cases
-you won't be dealing with an actual FITS file of a conditional image. You
+The 2nd popped operand (@file{binary.fits}) has to have @code{uint8} (or
address@hidden char} in standard C) type (see @ref{Numeric data types}). It
+is treated as a binary dataset (with only two values: zero and non-zero,
+hence the name @code{binary.fits} in this example).  However, commonly you
+won't be dealing with an actual FITS file of a condition/binary image. You
 will probably define the condition in the same run based on some other
 reference image and use the conditional and logical operators above to make
 a true/false (or one/zero) image for you internally. For example the case
@@ -8670,15 +8676,27 @@ $ astarithmetic in.fits reference.fits 100 gt new.fits 
where
 
 In the example above, any of the @file{in.fits} pixels that has a value in
 @file{reference.fits} greater than @command{100}, will be replaced with the
-corresponding pixel in @file{new.fits}. Finally, the input operands are
-read and used independently, so you can use the same file more than once as
-any of the operands.
+corresponding pixel in @file{new.fits}. Effectively the
address@hidden 100 gt} part created the condition/binary image which
+was added to the stack (in memory) and later used by @code{where}. The
+command above is thus equivalent to these two commands:
+
address@hidden
+$ astarithmetic reference.fits 100 gt --output=binary.fits
+$ astarithmetic in.fits binary.fits new.fits where
address@hidden example
+
+Finally, the input operands are read and used independently, so you can use
+the same file more than once as any of the operands.
 
-When the first popped operand (@file{if-true.fits}) is a single number, it
-can be a NaN value (or any blank value, depending on its type) like the
-example below (see @ref{Blank pixels}). In this example, all the pixels in
address@hidden that have a value greater than 100, will become blank
-in the natural data type of @file{in.fits}.
+When the 1st popped operand to @code{where} (@file{if-true.fits}) is a
+single number, it may be a NaN value (or any blank value, depending on its
+type) like the example below (see @ref{Blank pixels}). When the number is
+blank, it will be converted to the blank value of the type of the 3rd
+popped operand (@code{in.fits}). Hence, in the example below, all the
+pixels in @file{reference.fits} that have a value greater than 100, will
+become blank in the natural data type of @file{in.fits} (even though NaN
+values are only defined for floating point types).
 
 @example
 $ astarithmetic in.fits reference.fits 100 gt nan where
@@ -15885,7 +15903,7 @@ program} to easily define your own programs(s).
 
 @menu
 * Review of library fundamentals::  Guide on libraries and linking.
-* BuildProgram::                Link and run source files using Gnuastro's 
library.
+* BuildProgram::                Link and run source files with this library.
 * Gnuastro library::            Description of all library functions.
 * Library demo programs::       Demonstration for using libraries.
 @end menu
@@ -16609,7 +16627,7 @@ documentation will correspond to your installed version.
 
 @menu
 * Configuration information::   General information about library config.
-* Library data types::          Definitions and functions for types in 
Gnuastro.
+* Library data types::          Definitions and functions for types.
 * Library blank values::        Blank values and functions to deal with them.
 * Library data container::      General data container in Gnuastro.
 * Dimensions::                  Dealing with coordinates and dimensions.
@@ -17428,70 +17446,9 @@ for more on these wonderful high-level constructs.
 Pointer to the start of the complete allocated block of memory. When this
 pointer is not @code{NULL}, the dataset is not treated as a contiguous
 patch of memory. Rather, it is seen as covering only a portion of the
-larger patch of memory that @code{block} points to.
-
-In many contexts, it is desirable to slice the dataset into subsets or
-tiles (not necessarily overlapping). In such a way that you can work on
-each tile independently. One method would be to copy that region to a
-separate allocated space, but in many contexts this isn't necessary and
-infact can be a big burden on CPU/Memory usage. The @code{block} pointer in
address@hidden is defined for such situations: where allocation is not
-necessary. You just want to read the data or write to it independently (or
-in coordination with) other regions of the dataset. Added with parallel
-processing, this can greatly improve the time/memory consumption.
-
-See the figure below for example: assume the @code{larger} dataset is a
-contiguous block of memory that you are interpretting as a 2D array. But
-you only want to work on the smaller @code{tile} region.
-
address@hidden
-                            larger
-              ---------------------------------
-              |                               |
-              |              tile             |
-              |           ----------          |
-              |           |        |          |
-              |           |_       |          |
-              |           |*|      |          |
-              |           ----------          |
-              |       tile->block = larger    |
-              |_                              |
-              |*|                             |
-              ---------------------------------
address@hidden example
-
-To use @code{gal_data_t}'s @code{block} concept, you allocate a
address@hidden *tile} which is initialized with the pointer to the first
-element in the sub-array (as its @code{array} argument). Note that this is
-not necessarily the first element in the larger array. You can set the size
-of the tile along with the initialization as you please. Recall that, when
-given a address@hidden pointer as @code{array}, @code{gal_data_initialize}
-(and thus @code{gal_data_alloc}) do not allocate any space and just uses
-the given pointer for the new @code{array} element of the
address@hidden So your @code{tile} data structure will not be pointing
-to a separately allocated space.
-
-After the allocation is done, you just point @code{tile->block} to the
address@hidden dataset which hosts the full block of memory. Gnuastro's
-library will check the @code{block} pointer of their input dataset to see
-how to deal with dimensions and increments so they can always remain within
-the tile, see @ref{Tessellation library}.
-
-Since the block structure is defined as a pointer, arbitrary levels of
-tesselation/griding are possible (@code{tile->block} may itself be a tile
-in an even larger allocated space). Therefore, just like a linked-list (see
address@hidden lists}), it is important to have the @code{block} pointer of
-the largest dataset set to @code{NULL}. Normally, you won't have to worry
-about this, because @code{gal_data_initialize} (and thus
address@hidden) will set the @code{block} element to @code{NULL} by
-default (just remember not to change it). You can then only change the
address@hidden element for the tiles you define over the allocated space.
-
-The functions in @ref{Tessellation library} are defined to help you most
-effectively use/check/define a tessellation or tiles. This approach to
-dealing with parts of a larger block was inspired from the way the GNU
-Scientific Library (GSL) does it in its ``Vectors and Matrices'' chapter.
-
+larger patch of memory that @code{block} points to. See @ref{Tessellation
+library} for a more thorough explanation and functions to help work with
+tiles that are created from this pointer.
 @end table
 
 
@@ -18638,7 +18595,7 @@ functions in your code along with those discussed here.
 
 
 @menu
-* FITS macros errors filenames::  General macros, errors and checking FITS 
names
+* FITS macros errors filenames::  General macros, errors and checking names.
 * CFITSIO and Gnuastro types::  Conversion between FITS and Gnuastro types.
 * FITS HDUs::                   Opening and getting information about HDUs.
 * FITS header keywords::        Reading and writing FITS header keywords.
@@ -19416,9 +19373,839 @@ saying that the @code{filename} has been created.
 @node Arithmetic on datasets, Tessellation library, Table input output, 
Gnuastro library
 @subsection Arithmetic on datasets (@file{arithmetic.h})
 
+When the dataset's type and other information are already known, any
+programming language (including C) provides some very good tools for
+various operations (including arithmetic operations like addition) on the
+dataset with a simple loop. However, as an author of a program, making
+assumptions about the type of data, its dimensionality and other basic
+characteristics will come with a large processing burdern.
+
+For example if you always read your data as double precision floating
+points for a simple operation like addition with an integer constant, you
+will be wasting a lot of CPU and memory when the input dataset is
address@hidden type for example (see @ref{Numeric data types}). This overhead
+may be small for small images, but as you scale your process up and work
+with hundred/thousands of files that can be very large, this overhead will
+take a significant portion of the processing power. The functions and
+macros in this section are designed precisely for this purpose: to allow
+you to do any of the defined operations on any dataset with no overhead (in
+the native type of the dataset).
+
+Gnuastro's Arithmetic program uses the functions and macros of this
+section, so please also have a look at the @ref{Arithmetic} program and in
+particular @ref{Arithmetic operators} for a better description of the
+operators discussed here.
+
+The main function of this library is @code{gal_arithmetic} that is
+described below. It can take an arbitrary number of arguments as operands
+(depending on the operator, similar to @code{printf}). Its first two
+arguments are integers specifying the flags and operator. So first we will
+review the constants for the recognized flags and operators and discuss
+them, then introduce the actual function.
+
address@hidden  Macro GAL_ARITHMETIC_INPLACE
address@hidden Macro GAL_ARITHMETIC_FREE
address@hidden Macro GAL_ARITHMETIC_NUMOK
address@hidden Macro GAL_ARITHMETIC_FLAGS_ALL
address@hidden Bitwise Or
+Bit-wise flags to pass onto @code{gal_arithmetic} (see below). To pass
+multiple flags, use the bitwise-or operator, for example
address@hidden |
+GAL_ARITHMETIC_FREE}. @code{GAL_ARITHMETIC_FLAGS_ALL} is a combination of
+all flags to shorten your code if you want all flags activated. Each flag
+is described below:
address@hidden @code
address@hidden GAL_ARITHMETIC_INPLACE
+Do the operation in-place (in the input dataset, thus modifying it) to
+improve CPU and memory usage. If this flag is used, after
address@hidden finishes, the input dataset will be modified. It is
+thus useful if you have no more need for the input after the operation.
+
address@hidden GAL_ARITHMETIC_FREE
+Free (all the) input dataset(s) after the operation is done. Hence the
+inputs are no longer usable after @code{gal_arithmetic}.
+
address@hidden GAL_ARITHMETIC_NUMOK
+It is acceptable to use a number and an array together. For example if you
+want to add all the pixels in an image with a single number you can pass
+this flag to avoid having to allocate a constant array the size of the
+image (with all the pixels having the same number).
address@hidden table
address@hidden deffn
+
address@hidden  Macro GAL_ARITHMETIC_OP_PLUS
address@hidden Macro GAL_ARITHMETIC_OP_MINUS
address@hidden Macro GAL_ARITHMETIC_OP_MULTIPLY
address@hidden Macro GAL_ARITHMETIC_OP_DIVIDE
address@hidden Macro GAL_ARITHMETIC_OP_LT
address@hidden Macro GAL_ARITHMETIC_OP_LE
address@hidden Macro GAL_ARITHMETIC_OP_GT
address@hidden Macro GAL_ARITHMETIC_OP_GE
address@hidden Macro GAL_ARITHMETIC_OP_EQ
address@hidden Macro GAL_ARITHMETIC_OP_NE
address@hidden Macro GAL_ARITHMETIC_OP_AND
address@hidden Macro GAL_ARITHMETIC_OP_OR
+Binary operators (requiring two operands) that accept datasets of any
+recognized type (see @ref{Numeric data types}). When @code{gal_arithmetic}
+is called with any of these operators, it expects two datasets as
+arguments. For a full description of these operators with the same name,
+see @ref{Arithmetic operators}. The first dataset/operand will be put on
+the left of the operator and the second will be put on the right. The
+output type of the first four is determined from the input types (largest
+type of the inputs). The rest (which are all conditional operators) will
+output a binary @code{uint8_t} (or @code{unsigned char}) dataset with
+values of either @code{0} (zero) or @code{1} (one).
address@hidden deffn
+
address@hidden Macro GAL_ARITHMETIC_OP_NOT
+The logical NOT operator. When @code{gal_arithmetic} is called with this
+operator, it only expects one operand (dataset), since this is a unary
+operator. The output is @code{uint8_t} (or @code{unsigned char}) dataset of
+the same size as the input. Any non-zero element in the input will be
address@hidden (zero) in the output and any @code{0} (zero) will have a value of
address@hidden (one).
address@hidden deffn
+
address@hidden Macro GAL_ARITHMETIC_OP_ISBLANK
+A unary operator with output that is @code{1} for any element in the input
+that is blank, and @code{0} for any non-blank element. When
address@hidden is called with this operator, it will only expect one
+input dataset. The output dataset will have @code{uint8_t} (or
address@hidden char}) type.
+
address@hidden with this operator is just a wrapper for the
address@hidden function of @ref{Library blank values} and this
+operator is just included for completeness in arithmetic operations. So in
+your program, it might be easier to just call @code{gal_blank_flag}.
address@hidden deffn
+
address@hidden Macro GAL_ARITHMETIC_OP_WHERE
+The three-operand @emph{where} operator thoroughly discussed in
address@hidden operators}. When @code{gal_arithmetic} is called with this
+operator, it will only expect three input datasets: the first (which is the
+same as the returned dataset) is the array that will be modified. The
+second is the condition dataset (that must have a @code{uint8_t} or
address@hidden char} type), and the third is the value to be used if
+condition is non-zero.
+
+As a result, note that the order of operands when calling
address@hidden with @code{GAL_ARITHMETIC_OP_WHERE} is the opposite
+of running Gnuastro's Arithmetic program with the @code{where} operator
+(see @ref{Arithmetic}). This is because the latter uses the reverse-Polish
+notation which isn't necessary when calling a function (see @ref{Reverse
+polish notation}).
address@hidden deffn
+
address@hidden  Macro GAL_ARITHMETIC_OP_SQRT
address@hidden Macro GAL_ARITHMETIC_OP_LOG
address@hidden Macro GAL_ARITHMETIC_OP_LOG10
+Unary operator functions for calculating the square root
+(@mymath{\sqrt{i}}), @mymath{ln(i)} and @mymath{log(i)} mathematic
+operators on each element of the input dataset. The output will have the
+same type as the input, so if your inputs are integer types be careful.
+
+If you want your output to be floating point but your input is an integer
+type, you can convert the input to a floating point type with
address@hidden or
address@hidden(see @ref{Copying datasets}).
address@hidden deffn
+
address@hidden  Macro GAL_ARITHMETIC_OP_MINVAL
address@hidden Macro GAL_ARITHMETIC_OP_MAXVAL
address@hidden Macro GAL_ARITHMETIC_OP_NUMVAL
address@hidden Macro GAL_ARITHMETIC_OP_SUMVAL
address@hidden Macro GAL_ARITHMETIC_OP_MEANVAL
address@hidden Macro GAL_ARITHMETIC_OP_STDVAL
address@hidden Macro GAL_ARITHMETIC_OP_MEDIANVAL
+Unary operand statistical operators that will return a single value for
+datasets of any size. These are just wrappers around similar functions in
address@hidden operations} and are included in @code{gal_arithmetic} only
+for completeness (to use easily in @ref{Arithmetic}). In your programs, it
+will probably be easier if you use those @code{gal_statistics_} functions
+directly.
address@hidden deffn
+
address@hidden Macro GAL_ARITHMETIC_OP_ABS
+Unary operand absolute-value operator.
address@hidden deffn
+
address@hidden  Macro GAL_ARITHMETIC_OP_MIN
address@hidden Macro GAL_ARITHMETIC_OP_MAX
address@hidden Macro GAL_ARITHMETIC_OP_NUM
address@hidden Macro GAL_ARITHMETIC_OP_SUM
address@hidden Macro GAL_ARITHMETIC_OP_MEAN
address@hidden Macro GAL_ARITHMETIC_OP_STD
address@hidden Macro GAL_ARITHMETIC_OP_MEDIAN
+Multi-operand statistical operations. When @code{gal_arithmetic} is called
+with any of these operators, it will expect only a single operand that will
+be interpretted as a list of datasets (see @ref{List of gal_data_t}. The
+output will be a single dataset with each of its elements replaced by the
+respective statistical operation on the whole list. See the discussion
+under the @code{min} operator in @ref{Arithmetic operators}.
address@hidden deffn
+
address@hidden Macro GAL_ARITHMETIC_OP_POW
+Binary operator to-power operator. When @code{gal_arithmetic} is called
+with any of these operators, it will expect two operands: rasing the first
+by the second. This operator only accepts floating point inputs and the
+output is also floating point.
address@hidden deffn
+
address@hidden  Macro GAL_ARITHMETIC_OP_BITAND
address@hidden Macro GAL_ARITHMETIC_OP_BITOR
address@hidden Macro GAL_ARITHMETIC_OP_BITXOR
address@hidden Macro GAL_ARITHMETIC_OP_BITLSH
address@hidden Macro GAL_ARITHMETIC_OP_BITRSH
address@hidden Macro GAL_ARITHMETIC_OP_MODULO
+Binary integer-only operand operators. These operators are only defined on
+integer data types. When @code{gal_arithmetic} is called with any of these
+operators, it will expect two operands: the first is put on the left of the
+operator and the second on the right. The ones starting with @code{BIT} are
+the respective bit-wise operators in C and @code{MODULO} is the
+modulo/remainder operator. For a discussion on these operators, please see
address@hidden operators}.
+
+The output type is determined from the input types and C's internal
+conversions: it is strongly recommended that both inputs have the same type
+(any integer type), otherwise the bit-wise behavior will be determined by
+your compiler.
address@hidden deffn
+
address@hidden Macro GAL_ARITHMETIC_OP_BITNOT
+The unary bit-wise NOT operator. When @code{gal_arithmetic} is called with
+any of these operators, it will expect one operand of an integer type and
+preform the bitwise-NOT operation on it. The output will have the same type
+as the input.
address@hidden deffn
+
+
address@hidden  Macro GAL_ARITHMETIC_OP_TO_UINT8
address@hidden Macro GAL_ARITHMETIC_OP_TO_INT8
address@hidden Macro GAL_ARITHMETIC_OP_TO_UINT16
address@hidden Macro GAL_ARITHMETIC_OP_TO_INT16
address@hidden Macro GAL_ARITHMETIC_OP_TO_UINT32
address@hidden Macro GAL_ARITHMETIC_OP_TO_INT32
address@hidden Macro GAL_ARITHMETIC_OP_TO_UINT64
address@hidden Macro GAL_ARITHMETIC_OP_TO_INT64
address@hidden Macro GAL_ARITHMETIC_OP_TO_FLOAT32
address@hidden Macro GAL_ARITHMETIC_OP_TO_FLOAT64
+Unary type-conversion operators. When @code{gal_arithmetic} is called with
+any of these operators, it will expect one operand and convert it to the
+requested type. Note that with these operators, @code{gal_arithmetic} is
+just a wrapper over the @code{gal_data_copy_to_new_type} or
address@hidden that are discussed in @code{Copying
+datasets}. It accepts these operators only for completeness and easy usage
+in @ref{Arithmetic}. So in your programs, it might be preferrable to
+directly use those functions.
address@hidden deffn
+
+
address@hidden {gal_data_t *} gal_arithmetic (int operator, unsigned char 
flags, ...)
+Do the arithmetic operation of @code{operator} on the given operands (the
+third argument and any further argument). Certain special conditions can
+also be specified with the @code{flag} operator. The acceptable values for
address@hidden are defined in the macros above.
+
address@hidden is a multi-argument function (like C's
address@hidden). In other words, the number of necessary arguments is not
+fixed and depends on the value to @code{operator}. Here are a few examples
+showing this variability:
+
address@hidden
+out_1=gal_arithmetic(GAL_ARITHMETIC_OP_LOG,   0, in_1);
+out_2=gal_arithmetic(GAL_ARITHMETIC_OP_PLUS,  0, in_1, in_2);
+out_3=gal_arithmetic(GAL_ARITHMETIC_OP_WHERE, 0, in_1, in_2, in_3);
address@hidden example
+
+The number of necessary operands for each operator (and thus the number of
+necessary arguments to @code{gal_arithmetic}) are described above under
+each operator.
address@hidden deftypefun
+
 @node Tessellation library, Bounding box, Arithmetic on datasets, Gnuastro 
library
 @subsection Tessellation library (@file{tile.h})
 
+In many contexts, it is desirable to slice the dataset into subsets or
+tiles (overlapping or not). In such a way that you can work on each tile
+independently. One method would be to copy that region to a separate
+allocated space, but in many contexts this isn't necessary and infact can
+be a big burden on CPU/Memory usage. The @code{block} pointer in Gnuastro's
address@hidden data container} is defined for such situations: where
+allocation is not necessary. You just want to read the data or write to it
+independently (or in coordination with) other regions of the dataset. Added
+with parallel processing, this can greatly improve the time/memory
+consumption.
+
+See the figure below for example: assume the @code{larger} dataset is a
+contiguous block of memory that you are interpretting as a 2D array. But
+you only want to work on the smaller @code{tile} region.
+
address@hidden
+                            larger
+              ---------------------------------
+              |                               |
+              |              tile             |
+              |           ----------          |
+              |           |        |          |
+              |           |_       |          |
+              |           |*|      |          |
+              |           ----------          |
+              |       tile->block = larger    |
+              |_                              |
+              |*|                             |
+              ---------------------------------
address@hidden example
+
+To use @code{gal_data_t}'s @code{block} concept, you allocate a
address@hidden *tile} which is initialized with the pointer to the first
+element in the sub-array (as its @code{array} argument). Note that this is
+not necessarily the first element in the larger array. You can set the size
+of the tile along with the initialization as you please. Recall that, when
+given a address@hidden pointer as @code{array}, @code{gal_data_initialize}
+(and thus @code{gal_data_alloc}) do not allocate any space and just uses
+the given pointer for the new @code{array} element of the
address@hidden So your @code{tile} data structure will not be pointing
+to a separately allocated space.
+
+After the allocation is done, you just point @code{tile->block} to the
address@hidden dataset which hosts the full block of memory. Where relevant,
+Gnuastro's library functions will check the @code{block} pointer of their
+input dataset to see how to deal with dimensions and increments so they can
+always remain within the tile. The tools introduced in this section are
+designed to help in defining and working with tiles that are created in
+this manner.
+
+Since the block structure is defined as a pointer, arbitrary levels of
+tesselation/griding are possible (@code{tile->block} may itself be a tile
+in an even larger allocated space). Therefore, just like a linked-list (see
address@hidden lists}), it is important to have the @code{block} pointer of
+the largest (allocated) dataset set to @code{NULL}. Normally, you won't
+have to worry about this, because @code{gal_data_initialize} (and thus
address@hidden) will set the @code{block} element to @code{NULL} by
+default, just remember not to change it. You can then only change the
address@hidden element for the tiles you define over the allocated space.
+
+Below, we will first review constructs for @ref{Independent tiles} and then
+define the current approach to fully tessellating a dataset (or covering
+every pixel/data-element with a non-overlapping tile grid in @ref{Tile
+grid}. This approach to dealing with parts of a larger block was inspired
+from a similarly named concept in the GNU Scientific Library (GSL), see its
+``Vectors and Matrices'' chapter for their implementation.
+
+
+
address@hidden
+* Independent tiles::           Work on or check independent tiles.
+* Tile grid::                   Cover a full dataset with non-overlapping 
tiles.
address@hidden menu
+
address@hidden Independent tiles, Tile grid, Tessellation library, Tessellation 
library
address@hidden Independent tiles
+
+The most general application of tiles is to treat each independently, for
+example they may overlap, or they may not cover the full image. This
+section provides functions to help in checking/inspecting such tiles. In
address@hidden grid} we will discuss functions that define/work-with a tile grid
+(where the tiles don't overlap and fully cover the input
+dataset). Therefore, the functions in this section are general and can be
+used for the tiles produced by that section also.
+
address@hidden void gal_tile_start_coord (gal_data_t @code{*tile}, size_t 
@code{*start_coord})
+Calculate the starting coordinates of a tile in its allocated block of
+memory and write them in the memory that @code{start_coord} points to
+(which must have @code{tile->ndim} elements).
address@hidden deftypefun
+
address@hidden void gal_tile_start_end_coord (gal_data_t @code{*tile}, size_t 
@code{*start_end}, int @code{rel_block})
+Put the starting and ending (end point is not inclusive) coordinates of
address@hidden into the @code{start_end} array. It is assumed that a space of
address@hidden>ndim} has been already allocated (static or dynamic) for
address@hidden before this function is called.
+
address@hidden (or relative-to-block) is only relevant when @code{tile}
+has an intermediate tile between it and the allocated space (like a
+channel, see @code{gal_tile_full_two_layers}). If it doesn't
+(@code{tile->block} points the allocated dataset), then the value to
address@hidden is irrelevant.
+
+When @code{tile->block} is its self a larger block and @code{rel_block} is
+set to 0, then the starting and ending positions will be based on the
+position within @code{tile->block}, not the allocated space.
address@hidden deftypefun
+
address@hidden {void *} gal_tile_start_end_ind_inclusive (gal_data_t 
@code{*tile}, gal_data_t @code{*work}, size_t @code{*start_end_inc})
+Put the indexs of the first/start and last/end pixels (inclusive) in a tile
+into the @code{start_end} array (that must have two elements). NOTE: this
+function stores the index of each point, not its coordinates. It will then
+return the pointer to the start of the tile in the @code{work} data
+structure (which doesn't have to be equal to @code{tile->block}.
+
+The outputs of this function are defined to make it easy to parse over an
+n-dimensional tile. For example, this function is one of the most important
+parts of the internal processing of in @code{GAL_TILE_PARSE_OPERATE}
+function-like macro that is described below.
address@hidden deftypefun
+
address@hidden {gal_data_t *} gal_tile_series_from_minmax (gal_data_t 
@code{*block}, size_t @code{*minmax}, size_t @code{number})
+Construct a list of tile(s) given coordinates of the minimum and maximum of
+each tile. The minimum and maximums are assumed to be inclusive. The
+returned pointer is an allocated @code{gal_data_t} array that can later be
+freed with @code{gal_data_array_free} (see @ref{Arrays of
+datasets}). Internally, each element of the output array points to the next
+element, so the output may also be treated as a list of datasets (see
address@hidden of gal_data_t}) and passed onto the other functions described in
+this section.
+
+The array keeping the minmium and maximum coordinates for each tile must
+have the following format. So in total @code{minmax} must have
address@hidden elements.
+
address@hidden
+| min0_d0 | min0_d1 | max0_d0 | max0_d1 | ...
+                ... | minN_d0 | minN_d1 | maxN_d0 | maxN_d1 |
address@hidden example
address@hidden deftypefun
+
address@hidden {gal_data_t *} gal_tile_block (gal_data_t @code{*tile})
+Return the dataset that contains @code{tile}'s allocated block of
+memory. If tile is immediately defined as part of the allocated block, then
+this is equivalent to @code{tile->block}. However, it is possible to have
+multiple layers of tiles (where @code{tile->block} is itself a tile). So
+this function is the most generic way to get to the actual allocated
+dataset.
address@hidden deftypefun
+
address@hidden size_t gal_tile_block_increment (gal_data_t @code{*block}, 
size_t @code{*tsize}, size_t @code{num_increment}, size_t @code{*coord})
+Return the increment necessary to start at the next contiguous patch memory
+associated with a tile. @code{block} is the allocated block of memory and
address@hidden is the size of the tile along every dimension. If @code{coord}
+is @code{NULL}, it is ignored. Otherwise, it will contain the coordinate of
+the start of the next contiguous patch of memory.
+
+This function is intended to be used in a loop and @code{num_increment} is
+the main variable to this function. For the first time you call this
+function, it should be @code{1}. In subsequent calls (while you are parsing
+a tile), it should be increased by one.
address@hidden deftypefun
+
address@hidden {gal_data_t *} gal_tile_block_write_const_value (gal_data_t 
@code{*tilevalues}, gal_data_t @code{*tilesll}, int @code{initialize})
+Write a constant value for each tile over the area it covers in an
+allocated dataset that is the size of @code{tile}'s allocated block of
+memory (found through @code{gal_tile_block} described above). The arguments
+to this function are:
+
address@hidden @code
address@hidden tilevalues
+This must be an array that has the same number of elements as the nodes in
+in @code{tilesll} and in the same order that `tilesll' elements are parsed
+(from top to bottom, see @ref{Linked lists}). As a result the
+dimensionality of this array is irrelevant, it will be parsed contiguously.
+
address@hidden tilesll
+The list of input tiles (see @ref{List of gal_data_t}). Internally, it
+might be stored as an array (for example the output of
address@hidden described above), but this function
+doesn't care, it will parse the @code{next} elements to go to the next
+tile. This function will not pop-from or free the @code{tilesll}, it will
+only parse it from start to end.
+
address@hidden initialize
+Initialize the allocated space with blank values before writing in the
+constant values. This can be useful when the tiles don't cover the full
+allocated block.
address@hidden table
address@hidden deftypefun
+
address@hidden {gal_data_t *} gal_tile_block_check_tiles (gal_data_t 
@code{*tilesll})
+Make a copy of the memory block and fill it with the index of each tile in
address@hidden (counting from 0). The non-filled areas will have blank
+values. The output dataset will have a type of @code{GAL_TYPE_INT32} (see
address@hidden data types}).
+
+This function can be used when you want to check the coverage of each tile
+over the allocated block of memory. It is just a wrapper over the
address@hidden
address@hidden deftypefun
+
address@hidden {void *} gal_tile_block_relative_to_other (gal_data_t 
@code{*tile}, gal_data_t @code{*other})
+Return the pointer corresponding to the start of the region covered by
address@hidden over the @code{other} dataset. See the examples in
address@hidden for some example applications of this
+function.
address@hidden deftypefun
+
+
address@hidden void gal_tile_block_blank_flag (gal_data_t @code{*tilell}, 
size_t @code{numthreads})
+Check if each tile in the list has blank values and update its @code{flag}
+to mark this check and its result (see @ref{Generic data container}). The
+operation will be done on @code{numthreads} threads.
address@hidden deftypefun
+
+
address@hidden {Function-like macro} GAL_TILE_PARSE_OPERATE (@code{IN}, 
@code{OTHER}, @code{PARSE_OTHER}, @code{CHECK_BLANK}, @code{OP})
+Parse over @code{IN} (which can be a tile or a fully allocated block of
+memory) and do the @code{OP} operation on it (can be any combination of C
+expresssions). If @code{OTHER!=NULL}, this macro will allow access to its
+element(s) and it can optionally be parsed while parsing over
address@hidden You can use this to parse the same region over two arrays. The
+input arguments are (the expected types of each argument are also written
+here):
+
address@hidden @code
address@hidden IN (gal_data_t)
+Input dataset, this can be a tile or an allocated block of memory.
+
address@hidden OTHER (gal_data_t)
+Dataset (@code{gal_data_t}) to parse along with @code{IN}. It can be
address@hidden In that case, @code{o} (see description of @code{OP} below)
+will be @code{NULL} and should not be used. If @code{PARSE_OTHER} is zero,
+the size of this dataset is irrelevant. Otherwise, it has to have the same
+size as the allocated block of @code{IN}.
+
address@hidden PARSE_OTHER (int)
+Parse the other dataset along with the input. When this is non-zero and
address@hidden, then the @code{o} pointer will be incremented to cover
+the @code{OTHER} tile at the same rate as @code{i}, see description of
address@hidden for @code{i} and @code{o}.
+
address@hidden CHECK_BLANK (int)
+If it is non-zero, then the input will be checked for blank values and
address@hidden will only be called when we are not on a blank element.
+
address@hidden OP
+Operator: this can be any number of C experssions. This macro is going to
+define a @code{itype *i} variable which will increment over each element of
+the input array/tile. @code{itype} will be replaced with the C type that
+corresponds to the type of @code{INPUT}. As an example, if @code{INPUT}'s
+type is @code{GAL_DATA_UINT16} or @code{GAL_DATA_FLOAT32}, @code{i} will be
+defined as @code{uint16} or @code{float} respectively.
+
+This function-like macro will also define an @code{otype *o} which you can
+use to access an element of the @code{OTHER} dataset (if
address@hidden). @code{o} will correspond to the type of @code{OTHER}
+(similar to @code{itype} and @code{INPUT} discussed above). If
address@hidden is non-zero, then @code{o} will also be incremented to
+the same index element but in the other array. You can use these along with
+any other variable you define before this macro to process the input and
+store it in the other.
+
+All variables within this function-like macro begin with @code{tpo_} except
+for the three variables listed above. So as long as you don't start the
+names of your variables with this prefix everything will be fine. Note that
address@hidden (and possibly @code{o}) will be incremented once by this
+function-like macro, so don't increment them within @code{OP}. As a
+summary, the three variables you have access to within @code{OP} are:
+
address@hidden @code
address@hidden i
+Pointer to the element of @code{INPUT} that is being parsed with the proper
+type.
+
address@hidden o
+Pointer to the element of @code{OTHER} that is being parsed with the proper
+type. @code{o} can only be used if @code{OTHER!=NULL} and it will be
+parsed/incremented if @code{PARSE_OTHER} is non-zero.
+
address@hidden b
+Blank value in the type of @code{INPUT}.
address@hidden table
address@hidden table
+
+You can use a given tile (@code{tile} on a dataset that it was not
+initialized with (but has the same size, let's call it @code{new}) with the
+following steps:
+
address@hidden
+void *tarray;
+gal_data_t *tblock;
+
+/* `tile->block' must corrected AFTER `tile->array' */
+tarray      = tile->array;
+tblock      = tile->block;
+tile->array = gal_tile_block_relative_to_other(tile, new);
+tile->block = new;
+
+/* Parse and operate over this region of the `new' dataset. */
+GAL_TILE_PARSE_OPERATE(tile, NULL, 0, 0, @{
+    YOUR_PROCESSING;
+  @});
+
+/* Reset `tile->block' and `tile->array'. */
+tile->array=tarray;
+tile->block=tblock;
address@hidden example
+
+You can work on the same region of another block in one run of this
+function-like macro. To do that, you can make a fake tile and pass that as
+the @code{OTHER} argument. Below is a demonstration, @code{tile} is the
+actual tile that you start with and @code{new} is the other block of
+allocated memory.
+
address@hidden
+size_t zero=0;
+gal_data_t *faketile;
+
+/* Allocate the fake tile, these can be done outside a loop
+ * (over many tiles). */
+faketile=gal_data_alloc(NULL, new->type, 1, &zero,
+                        NULL, 0, -1, NULL, NULL, NULL);
+free(faketile->array);               /* To keep things clean. */
+free(faketile->dsize);               /* To keep things clean. */
+faketile->block = new;
+faketile->ndim  = new->ndim;
+
+/* These can be done in a loop (over many tiles). */
+faketile->size  = tile->size;
+faketile->dsize = tile->dsize;
+faketile->array = gal_tile_block_relative_to_other(tile, new);
+
+// Do your processing....
+GAL_TILE_PARSE_OPERATE(tile, faketile, 1, 1, @{
+    YOUR_PROCESSING_EXPRESSIONS;
+  @});
+
+// Clean up.
+bintile->array=NULL;
+bintile->dsize=NULL;
+gal_data_free(bintile);
address@hidden example
address@hidden deffn
+
+
+
address@hidden Tile grid,  , Independent tiles, Tessellation library
address@hidden Tile grid
+
+One very useful application of tiles is to completely cover an input
+dataset with tiles. Such that you know every pixel/data-element of the
+input image is covered by only one tile. The constructs in this section
+allow easy definition of such a tile structure. They will create lists of
+tiles that are also usable by the general tools discussed in
address@hidden tiles}.
+
+As discussed in @ref{Tessellation}, (mainly raw) astronomical images will
+mostly require two layers of tessellation, one for amplifier channels which
+all have the same size and another (smaller tile-size) tessellation over
+each channel. Hence, in this section we define a general structure to keep
+the main parameters of this two-layer tessellation and help in benefiting
+from it.
+
address@hidden {Type (C @code{struct})} gal_tile_two_layer_params
+This is the general structure to keep all the necessary parameters for a
+two-layer tessellation.
+
address@hidden
+struct gal_tile_two_layer_params
address@hidden
+  /* Inputs */
+  size_t             *tilesize;  /*******************************/
+  size_t          *numchannels;  /* These parameters have to be */
+  float          remainderfrac;  /* filled manually before      */
+  uint8_t           workoverch;  /* calling the functions in    */
+  uint8_t           checktiles;  /* this section.               */
+  uint8_t       oneelempertile;  /*******************************/
+
+  /* Internal parameters. */
+  size_t                  ndim;
+  size_t              tottiles;
+  size_t          tottilesinch;
+  size_t           totchannels;
+  size_t          *channelsize;
+  size_t             *numtiles;
+  size_t         *numtilesinch;
+  char          *tilecheckname;
+  size_t          *permutation;
+  size_t           *firsttsize;
+
+  /* Tile and channel arrays (which are also lists). */
+  gal_data_t            *tiles;
+  gal_data_t         *channels;
address@hidden;
address@hidden example
address@hidden deftp
+
address@hidden {size_t *} gal_tile_full (gal_data_t @code{*input}, size_t 
@code{*regular}, float @code{remainderfrac}, gal_data_t @code{**out}, size_t 
@code{multiple}, size_t @code{**firsttsize})
+Cover the full dataset with (mostly) identical tiles and return the number
+of tiles created along each dimension. The regular tile size (along each
+dimension) is determined from the @code{regular} array. If @code{input}'s
+size is not an exact multiple of @code{regular} for each dimension, then
+the tiles touching the edges in that dimension will have a different size
+to fully cover every element of the input (depending on
address@hidden).
+
+The output is an array with the same dimensions as @code{input} which
+contains the number of tiles along each dimension.  See @ref{Tessellation}
+for a description of its application in Gnuastro's programs and
address@hidden, just note that this function defines only onelayer of
+tiles.
+
+This is a low-level function (independent of the
address@hidden strcuture defined above). If you want a
+two-layer tessellation, directly call @code{gal_tile_full_two_layers} that
+is described below. The input arguments to this function are:
+
address@hidden @code
address@hidden input
+The main dataset (allocated block) which you want to create a tessellation
+over (only used for its sizes). So @code{input} may be a tile also.
+
address@hidden regular
+The the size of the regular tiles along each of the input's dimensions. So
+it must have the same number of elements as the dimensions of @code{input}
+(or @code{input->ndim}).
+
address@hidden remainderfrac
+The significant fraction of the remainder space to see if it should be
+split into two and put on both sides of a dimension or not. This is thus
+only relevant @code{input} length along a dimension isn't an exact multiple
+of the regular tile size along that dimension. See @ref{Tessellation} for a
+more thorough discussion.
+
address@hidden out
+Pointer to the array of data structures that will keep all the tiles (see
address@hidden of datasets}). If @code{*out==NULL}, then the necessary space
+to keep all the tiles will be allocated. If not, then all the tile
+information will be filled from the dataset that @code{*out} points to, see
address@hidden for more.
+
address@hidden multiple
+When @code{*out==NULL} (and thus will be allocated by this function),
+allocate space for @code{multiple} times the number of tiles needed. This
+can be very useful when you have several more identically sized
address@hidden, and you want all their tiles to be allocated (and thus
+indexed) together, even though they have different @code{block} datasets
+(that then link to one allocated space). See the definition of channels in
address@hidden and @code{gal_tile_full_two_layers} below.
+
address@hidden firsttsize
+The size of the first tile along every dimension. This is only different
+from the regular tile size when @code{regular} is not an exact multiple of
address@hidden's length along every dimension. This array is allocated
+internally by this function.
address@hidden table
address@hidden deftypefun
+
+
address@hidden void gal_tile_full_sanity_check (char @code{*filename}, char 
@code{*hdu}, gal_data_t @code{*input}, struct gal_tile_two_layer_params 
@code{*tl})
+Make sure that the input parameters (in @code{tl}, short for two-layer)
+correspond to the input dataset. @code{filename} and @code{hdu} are only
+required for error messages. Also, allocate and fill the
address@hidden>channelsize} array.
address@hidden deftypefun
+
address@hidden void gal_tile_full_two_layers (gal_data_t @code{*input}, struct 
gal_tile_two_layer_params @code{*tl})
+Create the two layered tessellation in @code{tl}.  The general set of steps
+you need to take to define the two-layered tessellation over an image can
+be seen in the example code below.
+
address@hidden
+gal_data_t *input;
+struct gal_tile_two_layer_params tl;
+char *filename="input.fits", *hdu="1";
+
+/* Set all the inputs shown in the structure definition. */
+...
+
+/* Read the input dataset. */
+input=gal_fits_img_read(filename, hdu, -1);
+
+/* Do a sanity check and preparations. */
+gal_tile_full_sanity_check(filename, hdu, input, &tl);
+
+/* Build the two-layer tessellation*/
+gal_tile_full_two_layers(input, &tl);
+
+/* `tl.tiles' and `tl.channels' are now a lists of tiles.*/
address@hidden example
address@hidden deftypefun
+
+
address@hidden void gal_tile_full_permutation (struct gal_tile_two_layer_params 
@code{*tl})
+Make a permutation to allow the conversion of tile location in memory to
+its location in the full input dataset and put it in
address@hidden>permutation}. If a permutation has already been defined for the
+tessellation, this function will not do anything. If permutation won't be
+necessary (there is only one channel or one dimension), then this function
+will not do anything (@code{tl->permutation} must have been initialized to
address@hidden).
+
+When there is only one channel OR one dimension, the tiles are allocated in
+memory in the same order that they represent the input data. However, to
+make channel-independent processing possible in a generic way, the tiles of
+each channel are allocated contiguously. So, when there is more than one
+channel AND more than one dimension, the index of the tile does not
+correspond to its position in the grid covering the input dataset.
+
+The example below may help clarify: assume you have a 6x6 tessellation with
+two channels in the horizontal and one in the vertical. On the left you can
+see how the tile IDs correspond to the input dataset. NOTE how `03' is on
+the second row, not on the first after `02'. On the right, you can see how
+the tiles are stored in memory (and shown if you simply write the array
+into a FITS file for example).
+
address@hidden
+   Corresponding to input               In memory
+   ----------------------             --------------
+     15 16 17 33 34 35               30 31 32 33 34 35
+     12 13 14 30 31 32               24 25 26 27 28 29
+     09 10 11 27 28 29               18 19 20 21 22 23
+     06 07 08 24 25 26      <--      12 13 14 15 16 17
+     03 04 05 21 22 23               06 07 08 09 10 11
+     00 01 02 18 19 20               00 01 02 03 04 05
address@hidden example
+
+As a result, if your values are stored in same order as the tiles, and you
+want them in over-all memory (for example to save as a FITS file), you need
+to permute the values:
+
address@hidden
+gal_permutation_apply(values, tl->permutation);
address@hidden example
+
+If you have values over-all and you want them in tile-order, you can apply
+the inverse permutation:
+
address@hidden
+gal_permutation_apply_inverse(values, tl->permutation);
address@hidden example
+
+Recall that this is the definition of permutation in this context:
+
address@hidden
+permute:    IN_ALL[ i       ]   =   IN_MEMORY[ perm[i] ]
+inverse:    IN_ALL[ perm[i] ]   =   IN_MEMORY[ i       ]
address@hidden example
address@hidden deftypefun
+
address@hidden void gal_tile_full_values_write (gal_data_t @code{*tilevalues}, 
struct gal_tile_two_layer_params @code{*tl}, char @code{*filename}, 
gal_fits_list_key_t @code{*keys}, char @code{*program_string})
+Write one value for each tile into a file. It is important to note that the
+values in @code{tilevalues} must be ordered in the same manner as the
+tiles, so @code{tilevalues->array[i]} is the value that should be given to
address@hidden>tiles[i]}. The @code{tl->permutation} array must have been
+initialized before calling this function with
address@hidden
address@hidden deftypefun
+
address@hidden {gal_data_t *} gal_tile_full_values_smooth (gal_data_t 
@code{*tilevalues}, struct gal_tile_two_layer_params @code{*tl}, size_t 
@code{width}, size_t @code{numthreads})
+Smooth the given values with a flat kernel of the given @code{width}. This
+cannot be done manually because if @code{tl->workoverch==0}, tiles in
+different channels must not be mixed/smoothed. Also the tiles are
+contiguous within the channel, not within the image, see the description
+under @code{gal_tile_full_permutation}.
address@hidden deftypefun
+
address@hidden size_t gal_tile_full_id_from_coord (struct 
gal_tile_two_layer_params @code{*tl}, size_t @code{*coord})
+Return the ID of the tile that corresponds to the coordinates
address@hidden Having this ID, you can use the @code{tl->tiles} array to get
+to the proper tile or read/write a value into an array that has one value
+per tile.
address@hidden deftypefun
+
address@hidden void gal_tile_full_free_contents (struct 
gal_tile_two_layer_params @code{*tl})
+Free all the allocated arrays within @code{tl}.
address@hidden deftypefun
+
+
 
 @node Bounding box, Git wrappers, Tessellation library, Gnuastro library
 @subsection Bounding box (@file{box.h})
diff --git a/lib/Makefile.am b/lib/Makefile.am
index ef281ea..d68448a 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -85,12 +85,12 @@ pkginclude_HEADERS = gnuastro/config.h 
$(headersdir)/arithmetic.h          \
 # will not distributed, so we need to explicitly tell Automake to
 # distribute them here.
 internaldir=$(top_srcdir)/lib/gnuastro-internal
-EXTRA_DIST = gnuastro.pc.in $(headersdir)/README $(internaldir)/README   \
-  $(internaldir)/arithmetic-binary.h $(internaldir)/arithmetic-onlyint.h \
-  $(internaldir)/checkset.h $(internaldir)/commonopts.h                  \
-  $(internaldir)/config.h.in $(internaldir)/fixedstringmacros.h          \
-  $(internaldir)/options.h $(internaldir)/tableintern.h                  \
-  $(internaldir)/timing.h
+EXTRA_DIST = gnuastro.pc.in $(headersdir)/README $(internaldir)/README    \
+  $(internaldir)/arithmetic-binary.h $(internaldir)/arithmetic-internal.h \
+  $(internaldir)/arithmetic-onlyint.h $(internaldir)/checkset.h           \
+  $(internaldir)/commonopts.h $(internaldir)/config.h.in                  \
+  $(internaldir)/fixedstringmacros.h $(internaldir)/options.h             \
+  $(internaldir)/tableintern.h $(internaldir)/timing.h
 
 
 
diff --git a/lib/arithmetic-binary.c b/lib/arithmetic-binary.c
index 886537e..651c023 100644
--- a/lib/arithmetic-binary.c
+++ b/lib/arithmetic-binary.c
@@ -29,6 +29,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 #include <gnuastro/arithmetic.h>
 
+#include <gnuastro-internal/arithmetic-internal.h>
 
 
 
diff --git a/lib/arithmetic-onlyint.c b/lib/arithmetic-onlyint.c
index 53db601..564c849 100644
--- a/lib/arithmetic-onlyint.c
+++ b/lib/arithmetic-onlyint.c
@@ -30,6 +30,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <gnuastro/arithmetic.h>
 
 #include <gnuastro-internal/arithmetic-onlyint.h>
+#include <gnuastro-internal/arithmetic-internal.h>
 
 
 
diff --git a/lib/arithmetic.c b/lib/arithmetic.c
index 969a9b0..d73e189 100644
--- a/lib/arithmetic.c
+++ b/lib/arithmetic.c
@@ -35,7 +35,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 #include <gnuastro-internal/arithmetic-binary.h>
 #include <gnuastro-internal/arithmetic-onlyint.h>
-
+#include <gnuastro-internal/arithmetic-internal.h>
 
 
 
@@ -1429,7 +1429,7 @@ gal_arithmetic(int operator, unsigned char flags, ...)
       break;
 
     case GAL_ARITHMETIC_OP_WHERE:
-      d1 = va_arg(va, gal_data_t *);    /* Output value/array.        */
+      d1 = va_arg(va, gal_data_t *);    /* To modify value/array.     */
       d2 = va_arg(va, gal_data_t *);    /* Condition (unsigned char). */
       d3 = va_arg(va, gal_data_t *);    /* If true value/array.       */
       arithmetic_where(flags, d1, d2, d3);
diff --git a/lib/binary.c b/lib/binary.c
index 8ac04af..ee3ced4 100644
--- a/lib/binary.c
+++ b/lib/binary.c
@@ -626,8 +626,8 @@ binary_make_padded_inverse(gal_data_t *input, gal_data_t 
**outtile)
 
   /* Fill the central regions. */
   in=input->array;
-  GAL_TILE_PARSE_OPERATE({*i = *in==GAL_BLANK_UINT8 ? *in : !*in; ++in;},
-                         tile, NULL, 0, 0);
+  GAL_TILE_PARSE_OPERATE( tile, NULL, 0, 0,
+                          {*i = *in==GAL_BLANK_UINT8 ? *in : !*in; ++in;} );
 
 
   /* Clean up and return. */
@@ -694,12 +694,12 @@ gal_binary_fill_holes(gal_data_t *input)
 
   /* The type of the tile is already known (it is `int32_t') and we have no
      output, so we'll just put `int' as a place-holder. In this way we can
-     avoid the switch statement of GAL_TILE_PARSE_OPERATE, and directly
-     use the workhorse macro `GAL_TILE_PO_OISET'. */
-  GAL_TILE_PO_OISET(int32_t, int, {
+     avoid the switch statement of GAL_TILE_PARSE_OPERATE, and directly use
+     the workhorse macro `GAL_TILE_PO_OISET'. */
+  GAL_TILE_PO_OISET(int32_t, int, tile, NULL, 0, 0, {
       *in = *i>1 && *i!=GAL_BLANK_INT32 ? 1 : *in;
       ++in;
-    }, tile, NULL, 0, 0);
+    });
 
 
   /* Clean up and return. */
diff --git a/lib/blank.c b/lib/blank.c
index 80ed2e2..3a21971 100644
--- a/lib/blank.c
+++ b/lib/blank.c
@@ -105,7 +105,7 @@ gal_blank_alloc_write(uint8_t type)
 void
 gal_blank_initialize(gal_data_t *input)
 {
-  GAL_TILE_PARSE_OPERATE({*i=b;}, input, NULL, 0, 0);
+  GAL_TILE_PARSE_OPERATE(input, NULL, 0, 0, {*i=b;});
 }
 
 
diff --git a/lib/gnuastro-internal/arithmetic-internal.h 
b/lib/gnuastro-internal/arithmetic-internal.h
new file mode 100644
index 0000000..34578a9
--- /dev/null
+++ b/lib/gnuastro-internal/arithmetic-internal.h
@@ -0,0 +1,74 @@
+/*********************************************************************
+Arithmetic -- Preform arithmetic operations on datasets.
+This is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2017, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#ifndef __GAL_ARITHMETIC_INTERNAL_H__
+#define __GAL_ARITHMETIC_INTERNAL_H__
+
+/* Include other headers if necessary here. Note that other header files
+   must be included before the C++ preparations below */
+#include <gnuastro/data.h>
+
+
+/* When we are within Gnuastro's building process, `IN_GNUASTRO_BUILD' is
+   defined. In the build process, installation information (in particular
+   `GAL_CONFIG_ARITH_CHAR' and the rest of the types that we needed in the
+   arithmetic function) is kept in `config.h'. When building a user's
+   programs, this information is kept in `gnuastro/config.h'. Note that all
+   `.c' files must start with the inclusion of `config.h' and that
+   `gnuastro/config.h' is only created at installation time (not present
+   during the building of Gnuastro).*/
+#ifndef IN_GNUASTRO_BUILD
+#include <gnuastro/config.h>
+#endif
+
+
+/* C++ Preparations */
+#undef __BEGIN_C_DECLS
+#undef __END_C_DECLS
+#ifdef __cplusplus
+# define __BEGIN_C_DECLS extern "C" {
+# define __END_C_DECLS }
+#else
+# define __BEGIN_C_DECLS                /* empty */
+# define __END_C_DECLS                  /* empty */
+#endif
+/* End of C++ preparations */
+
+
+
+/* Actual header contants (the above were for the Pre-processor). */
+__BEGIN_C_DECLS  /* From C++ preparations */
+
+int
+gal_arithmetic_binary_out_type(int operator, gal_data_t *l, gal_data_t *r);
+
+char *
+gal_arithmetic_operator_string(int operator);
+
+gal_data_t *
+gal_arithmetic_convert_to_compiled_type(gal_data_t *in, unsigned char flags);
+
+
+
+__END_C_DECLS    /* From C++ preparations */
+
+#endif           /* __GAL_ARITHMETIC_H__ */
diff --git a/lib/gnuastro/arithmetic.h b/lib/gnuastro/arithmetic.h
index 23b513f..5d50518 100644
--- a/lib/gnuastro/arithmetic.h
+++ b/lib/gnuastro/arithmetic.h
@@ -1,11 +1,11 @@
 /*********************************************************************
-data -- Structure and functions to represent/work with data
+Arithmetic -- Preform arithmetic operations on datasets.
 This is part of GNU Astronomy Utilities (Gnuastro) package.
 
 Original author:
      Mohammad Akhlaghi <address@hidden>
 Contributing author(s):
-Copyright (C) 2015, Free Software Foundation, Inc.
+Copyright (C) 2017, Free Software Foundation, Inc.
 
 Gnuastro is free software: you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
@@ -61,9 +61,9 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 
 
 /* Arithmetic flags. */
-#define GAL_ARITHMETIC_INPLACE  1
-#define GAL_ARITHMETIC_FREE     2
-#define GAL_ARITHMETIC_NUMOK    4
+#define GAL_ARITHMETIC_INPLACE  0x1
+#define GAL_ARITHMETIC_FREE     0x2
+#define GAL_ARITHMETIC_NUMOK    0x4
 
 #define GAL_ARITHMETIC_FLAGS_ALL ( GAL_ARITHMETIC_INPLACE        \
                                    | GAL_ARITHMETIC_FREE         \
@@ -136,23 +136,11 @@ enum gal_arithmetic_operators
 
 
 
-
-int
-gal_arithmetic_binary_out_type(int operator, gal_data_t *l, gal_data_t *r);
-
-char *
-gal_arithmetic_operator_string(int operator);
-
-gal_data_t *
-gal_arithmetic_convert_to_compiled_type(gal_data_t *in, unsigned char flags);
-
 gal_data_t *
 gal_arithmetic(int operator, unsigned char flags, ...);
 
 
 
-
-
 __END_C_DECLS    /* From C++ preparations */
 
 #endif           /* __GAL_ARITHMETIC_H__ */
diff --git a/lib/gnuastro/tile.h b/lib/gnuastro/tile.h
index ef4d882..0ae7af4 100644
--- a/lib/gnuastro/tile.h
+++ b/lib/gnuastro/tile.h
@@ -71,13 +71,11 @@ gal_tile_series_from_minmax(gal_data_t *block, size_t 
*minmax, size_t number);
 
 
 
-
-
 /***********************************************************************/
 /**************           Allocated block         **********************/
 /***********************************************************************/
 gal_data_t *
-gal_tile_block(gal_data_t *input);
+gal_tile_block(gal_data_t *tile);
 
 size_t
 gal_tile_block_increment(gal_data_t *block, size_t *tsize,
@@ -93,7 +91,8 @@ gal_tile_block_check_tiles(gal_data_t *tiles);
 void *
 gal_tile_block_relative_to_other(gal_data_t *tile, gal_data_t *other);
 
-
+void
+gal_tile_block_blank_flag(gal_data_t *tile_ll, size_t numthreads);
 
 
 
@@ -173,45 +172,45 @@ gal_tile_full_free_contents(struct 
gal_tile_two_layer_params *tl);
 /***********************************************************************/
 /**************           Function-like macros        ******************/
 /***********************************************************************/
-
-/* Useful when the input and output types are already known. We want this
-   to be self-sufficient (and be possible to call it independent of
-   `GAL_TILE_PARSE_OPERATE'), so some variables (basic definitions) are
-   re-defined here are in `GAL_TILE_PARSE_OPERATE'.*/
-#define GAL_TILE_PO_OISET(IT, OT, OP, IN, OUT, PARSE_OUT, CHECK_BLANK) { \
-    int parse_out=(OUT && PARSE_OUT);                                   \
-    size_t increment=0, num_increment=1;                                \
-    gal_data_t *out_w=OUT; /* `OUT' may be NULL. */                     \
-    gal_data_t *iblock = gal_tile_block(IN);                            \
-    IT b=0, *st=NULL, *i=IN->array, *f=i+IN->size;                      \
-    OT *ost=NULL, *o = out_w ? out_w->array : NULL;                     \
-    gal_data_t *oblock = OUT ? gal_tile_block(OUT) : NULL;              \
-    int hasblank = CHECK_BLANK ? gal_blank_present(IN, 0) : 0;          \
-    size_t s_e_ind[2]={0,iblock->size-1}; /* -1: this is INCLUSIVE */   \
+/* Useful when the input and other types are already known. We want this to
+   be self-sufficient (and be possible to call it independent of
+   `GAL_TILE_PARSE_OPERATE'), so some variables (basic definitions) that
+   are already defined in `GAL_TILE_PARSE_OPERATE' re-defined here. */
+#define GAL_TILE_PO_OISET(IT, OT, IN, OTHER, PARSE_OTHER, CHECK_BLANK, OP) { \
+    int tpo_parse_other=(OTHER && PARSE_OTHER);                         \
+    size_t tpo_increment=0, tpo_num_increment=1;                        \
+    gal_data_t *tpo_other_w=OTHER; /* `OTHER' may be NULL. */           \
+    gal_data_t *tpo_iblock = gal_tile_block(IN);                        \
+    IT b, *tpo_st=NULL, *i=IN->array, *tpo_f=i+IN->size;                \
+    OT *tpo_ost=NULL, *o = tpo_other_w ? tpo_other_w->array : NULL;     \
+    gal_data_t *tpo_oblock = OTHER ? gal_tile_block(OTHER) : NULL;      \
+    int tpo_hasblank = CHECK_BLANK ? gal_blank_present(IN, 0) : 0;      \
+    size_t tpo_s_e_i[2]={0,tpo_iblock->size-1}; /* -1: this is INCLUSIVE */ \
                                                                         \
-    /* Write the blank value for the input type into `b'). Note that */ \
-    /* a tile doesn't necessarily have to have a type. */               \
-    if(hasblank) gal_blank_write(&b, iblock->type);                     \
+    /* Write the blank value for the input type into `b'. */            \
+    gal_blank_write(&b, tpo_iblock->type);                              \
                                                                         \
     /* If this is a tile, not a full block. */                          \
-    if(IN!=iblock)                                                      \
+    if(IN!=tpo_iblock)                                                  \
       {                                                                 \
-        st=gal_tile_start_end_ind_inclusive(IN, iblock, s_e_ind);       \
-        if(parse_out)                                                   \
-          ost = (OT *)(oblock->array) + ( st - (IT *)(iblock->array) ); \
+        tpo_st = gal_tile_start_end_ind_inclusive(IN, tpo_iblock,       \
+                                                tpo_s_e_i);             \
+        if( tpo_parse_other )                                           \
+          tpo_ost = ( (OT *)(tpo_oblock->array)                         \
+                      + ( tpo_st - (IT *)(tpo_iblock->array) ) );       \
       }                                                                 \
                                                                         \
     /* Go over contiguous patches of memory. */                         \
-    while( s_e_ind[0] + increment <= s_e_ind[1] )                       \
+    while( tpo_s_e_i[0] + tpo_increment <= tpo_s_e_i[1] )               \
       {                                                                 \
                                                                         \
         /* If we are on a tile, reset `i' and `f'. Also, if there   */  \
-        /* is more than one element in `OUT', then set that. Note   */  \
+        /* is more than one element in `OTHER', then set that. Note */  \
         /* that it is upto the caller to increment `o' in `OP'.     */  \
-        if(IN!=iblock)                                                  \
+        if(IN!=tpo_iblock)                                              \
           {                                                             \
-            f = ( i = st + increment ) + IN->dsize[IN->ndim-1];         \
-            if(parse_out) o = ost + increment;                          \
+            tpo_f = ( i = tpo_st + tpo_increment ) + IN->dsize[IN->ndim-1]; \
+            if(tpo_parse_other) o = tpo_ost + tpo_increment;            \
           }                                                             \
                                                                         \
         /* Do the operation depending the nature of the blank value. */ \
@@ -223,23 +222,26 @@ gal_tile_full_free_contents(struct 
gal_tile_two_layer_params *tl);
         /* case, the only way to check if a data element is blank or */ \
         /* not is to see if the value of each element is equal to    */ \
         /* itself or not. */                                            \
-        if(hasblank)                                                    \
+        if(tpo_hasblank)                                                \
           {                                                             \
-            if(b==b) do{if(*i!=b) {OP;}if(parse_out) ++o;} while(++i<f); \
-            else     do{if(*i==*i){OP;}if(parse_out) ++o;} while(++i<f); \
+            if(b==b)                                                    \
+              do{if(*i!=b)  {OP;} if(tpo_parse_other) ++o;} while(++i<tpo_f);\
+            else                                                        \
+              do{if(*i==*i) {OP;} if(tpo_parse_other) ++o;} while(++i<tpo_f);\
           }                                                             \
-        else         do          {{OP;}if(parse_out) ++o;} while(++i<f); \
+        else                                                            \
+          do    {           {OP;} if(tpo_parse_other) ++o;} while(++i<tpo_f);\
                                                                         \
                                                                         \
         /* Set the incrementation. On a fully allocated iblock (when */ \
-        /* `IN==iblock'), we have already gone through the whole   */   \
+        /* `IN==tpo_iblock'), we have already gone through the whole */ \
         /* array, so we'll set the incrementation to the size of the */ \
         /* while block which will stop the `while' loop above. On a  */ \
         /* tile, we need to increment to the next contiguous patch   */ \
         /* of memory to continue parsing this tile. */                  \
-        increment += ( IN==iblock ? iblock->size                        \
-                       : gal_tile_block_increment(iblock, IN->dsize,    \
-                                                  num_increment++,      \
+        tpo_increment += ( IN==tpo_iblock ? tpo_iblock->size            \
+                       : gal_tile_block_increment(tpo_iblock, IN->dsize, \
+                                                  tpo_num_increment++,  \
                                                   NULL) );              \
       }                                                                 \
                                                                         \
@@ -249,43 +251,43 @@ gal_tile_full_free_contents(struct 
gal_tile_two_layer_params *tl);
   }
 
 
-#define GAL_TILE_PO_OSET(OT, OP, IN, OUT, PARSE_OUT, CHECK_BLANK) {     \
-  switch(iblock->type)                                                  \
+#define GAL_TILE_PO_OSET(OT, IN, OTHER, PARSE_OTHER, CHECK_BLANK, OP) { \
+  switch(tpo_iblock->type)                                              \
     {                                                                   \
     case GAL_TYPE_UINT8:                                                \
-      GAL_TILE_PO_OISET(uint8_t,  OT,OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+      GAL_TILE_PO_OISET(uint8_t,  OT,IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
       break;                                                            \
     case GAL_TYPE_INT8:                                                 \
-      GAL_TILE_PO_OISET(int8_t,   OT,OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+      GAL_TILE_PO_OISET(int8_t,   OT,IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
       break;                                                            \
     case GAL_TYPE_UINT16:                                               \
-      GAL_TILE_PO_OISET(uint16_t, OT,OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+      GAL_TILE_PO_OISET(uint16_t, OT,IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
       break;                                                            \
     case GAL_TYPE_INT16:                                                \
-      GAL_TILE_PO_OISET(int16_t,  OT,OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+      GAL_TILE_PO_OISET(int16_t,  OT,IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
       break;                                                            \
     case GAL_TYPE_UINT32:                                               \
-      GAL_TILE_PO_OISET(uint32_t, OT,OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+      GAL_TILE_PO_OISET(uint32_t, OT,IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
       break;                                                            \
     case GAL_TYPE_INT32:                                                \
-      GAL_TILE_PO_OISET(int32_t,  OT,OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+      GAL_TILE_PO_OISET(int32_t,  OT,IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
       break;                                                            \
     case GAL_TYPE_UINT64:                                               \
-      GAL_TILE_PO_OISET(uint64_t, OT,OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+      GAL_TILE_PO_OISET(uint64_t, OT,IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
       break;                                                            \
     case GAL_TYPE_INT64:                                                \
-      GAL_TILE_PO_OISET(int64_t,  OT,OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+      GAL_TILE_PO_OISET(int64_t,  OT,IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
       break;                                                            \
     case GAL_TYPE_FLOAT32:                                              \
-      GAL_TILE_PO_OISET(float,    OT,OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+      GAL_TILE_PO_OISET(float,    OT,IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
       break;                                                            \
     case GAL_TYPE_FLOAT64:                                              \
-      GAL_TILE_PO_OISET(double,   OT,OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+      GAL_TILE_PO_OISET(double,   OT,IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
       break;                                                            \
     default:                                                            \
-      {                                                                 \
-        fprintf(stderr, "type code %d not recognized in "               \
-              "`GAL_TILE_PO_OSET'", iblock->type);                      \
+      { /* `error' function might not be available for the user. */     \
+        fprintf(stderr, "GAL_TILE_PO_OSET: type code %d not recognized",\
+                tpo_iblock->type);                                      \
         exit(EXIT_FAILURE);                                             \
       }                                                                 \
     }                                                                   \
@@ -293,159 +295,75 @@ gal_tile_full_free_contents(struct 
gal_tile_two_layer_params *tl);
 
 
 /* Parse over a region of memory (can be an n-dimensional tile or a fully
-   allocated block of memory) and do a certain operation. If `OUT' is not
-   NULL, it can also save the output of the operation into the `gal_data_t'
-   that it points to. Note that OUT must either have only one element (for
-   the whole input) or have exactly the same number of elements as the
-   input (one value for one pixel/element of the input). The input
-   arguments are:
-
-       `OP': Operator: this can be any number of C experssions. This macro
-             is going to define an `IT *i' variable which will increment
-             over each element of the input array/tile. It will also define
-             an `OT *o' which you can use to access the output. If
-             `PARSE_OUT' is non-zero, then `o' will also be incremented to
-             the same index element but in the output array. You can use
-             these along with any other variable you define before this
-             macro to process the input and store it in the output. Note
-             that `i' and `o' will be incremented once in here, so don't
-             increment them in `OP'.
-
-       `IN': Input `gal_data_t', can be a tile or an allocated block of
-             memory.
-
-       `OUT': Output `gal_data_t'. It can be NULL. In that case, `o' will
-             be NULL and should not be used. If given,
-
-       `PARSE_OUT': Parse the output along with the input. When this is
-             non-zero, then the `o' pointer (described in `OP') will be
-             incremented to cover the same region of the input in the
-             output.
-
-       `CHECK_BLANK': If it is non-zero, then the input will be checked for
-             blank values.
-
-   For `OP' you have access to some other variables besides `i' and `o':
-
-      `i': Pointer to this element of input to parse.
-
-      `o': Pointer to corresponding element in output.
-
-      `b': blank value in input't type.
-
-   See `lib/statistics.c' for some example applications of this function.
-
-  -----------
-  TIPS/TRICKS
-  -----------
-
-  You can use a given tile on a dataset that it was not initialized with
-  (but has the same size). You can do that like this:
-
-     void *tarray;
-     gal_data_t *tblock;
-
-     tarray=tile->array;
-     tblock=tile->block;
-     tile->array=gal_tile_block_relative_to_other(tile, THE_OTHER_DATASET);
-     tile->block=THE_OTHER_DATASET;  <<-- `tile->block' must corrected
-                                          AFTER `tile->array'.
-     GAL_TILE_PARSE_OPERATE(...)
-
-     tile->array=tarray;
-     tile->block=tblock;
-
-  You can work on one other array while working on the one that tile
-  actually points to. To do that, you can make a fake tile and pass that as
-  the `OUT' argument to this macro. While the name is `OUT' it can be used
-  in any manner you like. To do this, you can take the following steps. In
-  this example, `tile' is the actual tile that you have.
-
-     gal_data_t *faketile;
-
-     // These can be done outside a loop.
-     faketile=gal_data_alloc(NULL, OTHER_DATASET->type, 1, &dsize,
-                            NULL, 0, -1, NULL, NULL, NULL);
-     free(faketile->array);
-     free(faketile->dsize);
-     faketile->block=OTHER_DATASET;
-     faketile->ndim=OTHER_DATASET->ndim;
-
-     // These can be done in the loop over tiles.
-     faketile->size=tile->size;
-     faketile->dsize=tile->dsize;
-     faketile->array=gal_tile_block_relative_to_other(tile, OTHER_DATASET);
-
-     // Do your processing....
-     GAL_TILE_PARSE_OPERATE(PROCESSING, tile, faketile, 1, 1);
-
-     // Clean up.
-     bintile->array=NULL;
-     bintile->dsize=NULL;
-     gal_data_free(bintile);
-*/
-#define GAL_TILE_PARSE_OPERATE(OP, IN, OUT, PARSE_OUT, CHECK_BLANK) {   \
-    int parse_out=(OUT && PARSE_OUT);                                   \
-    gal_data_t *iblock = gal_tile_block(IN);                            \
-    gal_data_t *oblock = OUT ? gal_tile_block(OUT) : NULL;              \
+   allocated block of memory) and do a certain operation. If `OTHER' is not
+   NULL, this macro will also parse it at the same time . Note that OTHER
+   must either have only one element (for the whole input) or have exactly
+   the same number of elements as the input (one value for one
+   pixel/element of the input). See the documentation for more on this
+   macro and some examples. */
+#define GAL_TILE_PARSE_OPERATE(IN, OTHER, PARSE_OTHER, CHECK_BLANK, OP) { \
+    int tpo_parse_other=(OTHER && PARSE_OTHER);                         \
+    gal_data_t *tpo_iblock = gal_tile_block(IN);                        \
+    gal_data_t *tpo_oblock = OTHER ? gal_tile_block(OTHER) : NULL;      \
                                                                         \
     /* A small sanity check. */                                         \
-    if( parse_out && gal_data_dsize_is_different(iblock, oblock) )      \
+    if( tpo_parse_other                                                 \
+        && gal_data_dsize_is_different(tpo_iblock, tpo_oblock) )        \
       {                                                                 \
         /* The `error' function, is a GNU extension. */                 \
-        fprintf(stderr, "when `PARSE_OUT' is non-zero, the "            \
-                "allocated block size of the input and output of "      \
-                "`GAL_TILE_PARSE_OPERATE' must be equal, but they are " \
-                "not: %zu and %zu elements respectively)",              \
-                iblock->size, oblock->size);                            \
+        fprintf(stderr, "GAL_TILE_PARSE_OPERATE: when `PARSE_OTHER' is "\
+                "non-zero, the allocated block size of `IN' and "       \
+                "`OTHER' must be equal, but they are not: %zu and %zu " \
+                "elements respectively)", tpo_iblock->size,             \
+                tpo_oblock->size);                                      \
         exit(EXIT_FAILURE);                                             \
       }                                                                 \
                                                                         \
-    /* First set the OUTPUT type. */                                    \
-    if(OUT)                                                             \
-      switch(oblock->type)                                              \
+    /* First set the OTHER type. */                                     \
+    if(OTHER)                                                           \
+      switch(tpo_oblock->type)                                          \
         {                                                               \
         case GAL_TYPE_UINT8:                                            \
-          GAL_TILE_PO_OSET(uint8_t,  OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+          GAL_TILE_PO_OSET(uint8_t, IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
           break;                                                        \
         case GAL_TYPE_INT8:                                             \
-          GAL_TILE_PO_OSET(int8_t,   OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+          GAL_TILE_PO_OSET(int8_t,  IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
           break;                                                        \
         case GAL_TYPE_UINT16:                                           \
-          GAL_TILE_PO_OSET(uint16_t, OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+          GAL_TILE_PO_OSET(uint16_t,IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
           break;                                                        \
         case GAL_TYPE_INT16:                                            \
-          GAL_TILE_PO_OSET(int16_t,  OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+          GAL_TILE_PO_OSET(int16_t, IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
           break;                                                        \
         case GAL_TYPE_UINT32:                                           \
-          GAL_TILE_PO_OSET(uint32_t, OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+          GAL_TILE_PO_OSET(uint32_t,IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
           break;                                                        \
         case GAL_TYPE_INT32:                                            \
-          GAL_TILE_PO_OSET(int32_t,  OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+          GAL_TILE_PO_OSET(int32_t, IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
           break;                                                        \
         case GAL_TYPE_UINT64:                                           \
-          GAL_TILE_PO_OSET(uint64_t, OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+          GAL_TILE_PO_OSET(uint64_t,IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
           break;                                                        \
         case GAL_TYPE_INT64:                                            \
-          GAL_TILE_PO_OSET(int64_t,  OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+          GAL_TILE_PO_OSET(int64_t, IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
           break;                                                        \
         case GAL_TYPE_FLOAT32:                                          \
-          GAL_TILE_PO_OSET(float,    OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+          GAL_TILE_PO_OSET(float,   IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
           break;                                                        \
         case GAL_TYPE_FLOAT64:                                          \
-          GAL_TILE_PO_OSET(double,   OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+          GAL_TILE_PO_OSET(double,  IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
           break;                                                        \
         default:                                                        \
           {                                                             \
             fprintf(stderr, "type code %d not recognized in "           \
-                    "`GAL_TILE_PARSE_OPERATE'", oblock->type);          \
+                    "`GAL_TILE_PARSE_OPERATE'", tpo_oblock->type);      \
             exit(EXIT_FAILURE);                                         \
           }                                                             \
         }                                                               \
     else                                                                \
-      /* When `OUT==NULL', its type is irrelevant, we'll just use */    \
+      /* When `OTHER==NULL', its type is irrelevant, we'll just use */  \
       /*`int' as a place holder. */                                     \
-      GAL_TILE_PO_OSET(int,          OP,IN,OUT,PARSE_OUT,CHECK_BLANK);  \
+      GAL_TILE_PO_OSET(int,         IN,OTHER,PARSE_OTHER,CHECK_BLANK,OP); \
   }
 
 
diff --git a/lib/statistics.c b/lib/statistics.c
index 8922fe4..8db333e 100644
--- a/lib/statistics.c
+++ b/lib/statistics.c
@@ -58,17 +58,20 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 gal_data_t *
 gal_statistics_number(gal_data_t *input)
 {
+  uint64_t counter=0;
   size_t dsize=1;
   gal_data_t *out=gal_data_alloc(NULL, GAL_TYPE_UINT64, 1, &dsize,
                                  NULL, 1, -1, NULL, NULL, NULL);
 
   /* If there is no blank values in the input, then the total number is
      just the size. */
-  if(gal_blank_present(input, 0))
-    { GAL_TILE_PARSE_OPERATE({++(*o);}, input, out, 0, 1) }
+  if(gal_blank_present(input, 0)) /* `{}' necessary for `else'. */
+    { GAL_TILE_PARSE_OPERATE(input, NULL, 0, 1, {++counter;}); }
   else
-    *((uint64_t *)(out->array)) = input->size;
+    counter = input->size;
 
+  /* Write the value into memory. */
+  *((uint64_t *)(out->array)) = counter;
   return out;
 }
 
@@ -91,7 +94,7 @@ gal_statistics_minimum(gal_data_t *input)
   gal_type_max(out->type, out->array);
 
   /* Parse the full input. */
-  GAL_TILE_PARSE_OPERATE({*o = *i < *o ? *i : *o; ++n;}, input, out, 0, 0);
+  GAL_TILE_PARSE_OPERATE(input, out, 0, 0, {*o = *i < *o ? *i : *o; ++n;});
 
   /* If there were no usable elements, set the output to blank, then
      return. */
@@ -116,7 +119,7 @@ gal_statistics_maximum(gal_data_t *input)
   gal_type_min(out->type, out->array);
 
   /* Parse the full input. */
-  GAL_TILE_PARSE_OPERATE({*o = *i > *o ? *i : *o; ++n;}, input, out, 0, 0);
+  GAL_TILE_PARSE_OPERATE(input, out, 0, 0, {*o = *i > *o ? *i : *o; ++n;});
 
   /* If there were no usable elements, set the output to blank, then
      return. */
@@ -139,7 +142,7 @@ gal_statistics_sum(gal_data_t *input)
 
   /* Parse the dataset. Note that in `gal_data_alloc' we set the `clear'
      flag to 1, so it will be 0.0f. */
-  GAL_TILE_PARSE_OPERATE({++n; *o += *i;}, input, out, 0, 1);
+  GAL_TILE_PARSE_OPERATE(input, out, 0, 1, {++n; *o += *i;});
 
   /* If there were no usable elements, set the output to blank, then
      return. */
@@ -162,7 +165,7 @@ gal_statistics_mean(gal_data_t *input)
 
   /* Parse the dataset. Note that in `gal_data_alloc' we set the `clear'
      flag to 1, so it will be 0.0f. */
-  GAL_TILE_PARSE_OPERATE({++n; *o += *i;}, input, out, 0, 1);
+  GAL_TILE_PARSE_OPERATE(input, out, 0, 1, {++n; *o += *i;});
 
   /* Above, we calculated the sum and number, so if there were any elements
      in the dataset (`n!=0'), divide the sum by the number, otherwise, put
@@ -187,7 +190,7 @@ gal_statistics_std(gal_data_t *input)
                                  NULL, 1, -1, NULL, NULL, NULL);
 
   /* Parse the input. */
-  GAL_TILE_PARSE_OPERATE({++n; s += *i; s2 += *i * *i;}, input, out, 0, 1);
+  GAL_TILE_PARSE_OPERATE(input, out, 0, 1, {++n; s += *i; s2 += *i * *i;});
 
   /* Write the standard deviation into the output. */
   *((double *)(out->array)) = n ? sqrt( (s2-s*s/n)/n ) : GAL_BLANK_FLOAT64;
@@ -210,7 +213,7 @@ gal_statistics_mean_std(gal_data_t *input)
                                  NULL, 1, -1, NULL, NULL, NULL);
 
   /* Parse the input. */
-  GAL_TILE_PARSE_OPERATE({++n; s += *i; s2 += *i * *i;}, input, out, 0, 1);
+  GAL_TILE_PARSE_OPERATE(input, out, 0, 1, {++n; s += *i; s2 += *i * *i;});
 
   /* Write in the output values and return. */
   ((double *)(out->array))[0] = n ? s/n                  : GAL_BLANK_FLOAT64;
diff --git a/lib/tile.c b/lib/tile.c
index b6f061f..24b4029 100644
--- a/lib/tile.c
+++ b/lib/tile.c
@@ -297,10 +297,10 @@ gal_tile_series_from_minmax(gal_data_t *block, size_t 
*minmax, size_t number)
    the block pointer and return the `dsize' element of lowest-level
    structure. */
 gal_data_t *
-gal_tile_block(gal_data_t *input)
+gal_tile_block(gal_data_t *tile)
 {
-  while(input->block!=NULL) input=input->block;
-  return input;
+  while(tile->block!=NULL) tile=tile->block;
+  return tile;
 }
 
 
@@ -308,9 +308,7 @@ gal_tile_block(gal_data_t *input)
 
 
 /* Return the increment necessary to start at the next series of contiguous
-   memory (fastest dimension) associated with a tile. See
-   `gal_tile_block_check_tiles' as one example application of this
-   function.
+   memory (fastest dimension) associated with a tile.
 
    1D and 2D cases are simple and need no extra explanation, but the case
    for higher dimensions can be alittle more complicated, So we will go
@@ -409,7 +407,7 @@ gal_tile_block_increment(gal_data_t *block, size_t *tsize,
         dimensionality of this array is irrelevant. Note that unlike
         `tiles', `tilevalues' must be an array.
 
-     `tiles': This will be parsed as a linked list (using the `next'
+     `tilesll': This will be parsed as a linked list (using the `next'
         element). Internally, it might be stored as an array, but this
         function doesn't care! The position of the tile over its block will
         be determined according to the `block' element and the pointer of
@@ -457,15 +455,16 @@ gal_tile_block_write_const_value(gal_data_t *tilevalues, 
gal_data_t *tilesll,
         }
     }
 
-  /* Go over the tiles and write the values in. Note Recall that `tofill'
-     has the same type as `tilevalues'. So we are using memcopy. */
+  /* Go over the tiles and write the values in. Recall that `tofill' has
+     the same type as `tilevalues'. So we are using memcopy. */
   tile_ind=0;
   for(tile=tilesll; tile!=NULL; tile=tile->next)
     {
       /* Set the pointer to use as input. */
       in=gal_data_ptr_increment(tilevalues->array, tile_ind++, type);;
-      GAL_TILE_PARSE_OPERATE({memcpy(o, in, gal_type_sizeof(type));},
-                             tile, tofill, 1, 0);
+      GAL_TILE_PARSE_OPERATE( tile, tofill, 1, 0, {
+          memcpy(o, in, gal_type_sizeof(type));
+        } );
     }
 
   return tofill;
@@ -475,12 +474,9 @@ gal_tile_block_write_const_value(gal_data_t *tilevalues, 
gal_data_t *tilesll,
 
 
 
-/* Make a copy of the memory block in integer type and fill it with the ID
-   of each tile, the non-filled areas have blank values. Finally, save the
-   final array into a FITS file, specified with `filename'. This is done
-   mainly for inspecting the positioning of tiles. We are using a signed
-   32-bit type because this is the standard FITS standard type for
-   integers. */
+/* Make a copy of the memory block and fill it with the index of each tile
+   in `tilesll' (counting from 0). The non-filled areas will have blank
+   values. The output dataset will have a type of `GAL_TYPE_INT32'. */
 gal_data_t *
 gal_tile_block_check_tiles(gal_data_t *tilesll)
 {
@@ -523,6 +519,45 @@ gal_tile_block_relative_to_other(gal_data_t *tile, 
gal_data_t *other)
 
 
 
+/* To use within `gal_tile_full_blank_flag'. */
+static void *
+tile_block_blank_flag(void *in_prm)
+{
+  struct gal_threads_params *tprm=(struct gal_threads_params *)in_prm;
+  gal_data_t *tile_ll=(gal_data_t *)(tprm->params);
+
+  size_t i;
+  gal_data_t *tile;
+
+  /* Check all the tiles given to this thread. */
+  for(i=0; tprm->indexs[i] != GAL_BLANK_SIZE_T; ++i)
+    {
+      tile=&tile_ll[ tprm->indexs[i] ];
+      gal_blank_present(tile, 1);
+    }
+
+  /* Wait for all the other threads to finish. */
+  if(tprm->b) pthread_barrier_wait(tprm->b);
+  return NULL;
+}
+
+
+
+
+
+/* Update the blank flag on the tiles within the list of input tiles. */
+void
+gal_tile_block_blank_flag(gal_data_t *tile_ll, size_t numthreads)
+{
+  /* Go over all the tiles and update their blank flag. */
+  gal_threads_spin_off(tile_block_blank_flag, tile_ll,
+                       gal_list_data_number(tile_ll), numthreads);
+}
+
+
+
+
+
 
 
 
@@ -663,6 +698,11 @@ gal_tile_full_regular_first(gal_data_t *parent, size_t 
*regular,
         though they have different `block' datasets (that then link to one
         allocated space).  See the `gal_tile_full_two_layers' below.
 
+     `firsttsize': The size of the first tile along every dimension. This
+        is only different from the regular tile size when `regular' is not
+        an exact multiple of `input''s length along every dimension. This
+        array is allocated internally by this function.
+
    Output
    ------
 
@@ -682,8 +722,7 @@ gal_tile_full_regular_first(gal_data_t *parent, size_t 
*regular,
            block in each dimension.
 
         2. parent-size (or `psize') which is the size of the parent in each
-           dimension (we don't want to go out of the paren't range).
-*/
+           dimension (we don't want to go out of the paren't range). */
 size_t *
 gal_tile_full(gal_data_t *input, size_t *regular,
               float remainderfrac, gal_data_t **out, size_t multiple,
@@ -970,50 +1009,7 @@ gal_tile_full_two_layers(gal_data_t *input,
    `permutation' element. If a permutation has already been defined for the
    tessellation, this function will not do anythin. If permutation won't be
    necessary, then this function will just return (the permutation must
-   have been initialized to NULL).
-
-
-   Theory
-   ------
-
-   When there is only one channel OR one dimension, the tiles are allocated
-   in memory in the same order that they represent the input data. However,
-   to make channel-independent processing possible in a generic way, the
-   tiles of each channel are allocated contiguously. So, when there is more
-   than one channel AND more than one dimension, the index of the tile does
-   not correspond to its position in the grid covering the input dataset.
-
-   The example below may help clarify: assume you have a 6x6 tessellation
-   with two channels in the horizontal and one in the vertical. On the left
-   you can see how the tile IDs correspond to the input dataset. NOTE how
-   `03' is on the second row, not on the first after `02'. On the right,
-   you can see how the tiles are stored in memory (and shown if you simply
-   write the array into a FITS file for example).
-
-           Corresponding to input                 In memory
-           ----------------------               --------------
-              15 16 17 33 34 35               30 31 32 33 34 35
-              12 13 14 30 31 32               24 25 26 27 28 29
-              09 10 11 27 28 29               18 19 20 21 22 23
-              06 07 08 24 25 26     <--       12 13 14 15 16 17
-              03 04 05 21 22 23               06 07 08 09 10 11
-              00 01 02 18 19 20               00 01 02 03 04 05
-
-   As a result, if your values are stored in same order as the tiles, and
-   you want them in over-all memory (for example to save as a FITS file),
-   you need to permute the values:
-
-      gal_permutation_apply(values, tl->permutation);
-
-   If you have values over-all and you want them in tile-order, you can
-   apply the inverse permutation:
-
-      gal_permutation_apply_inverse(values, tl->permutation);
-
-   Recall that this is the definition of permutation in this context:
-
-       permute:    IN_ALL[ i       ]   =   IN_MEMORY[ perm[i] ]
-       inverse:    IN_ALL[ perm[i] ]   =   IN_MEMORY[ i       ]         */
+   have been initialized to NULL). */
 void
 gal_tile_full_permutation(struct gal_tile_two_layer_params *tl)
 {
@@ -1217,45 +1213,6 @@ gal_tile_full_id_from_coord(struct 
gal_tile_two_layer_params *tl,
 
 
 
-/* To use within `gal_tile_full_blank_bit'. */
-static void *
-tile_full_blank_flag(void *in_prm)
-{
-  struct gal_threads_params *tprm=(struct gal_threads_params *)in_prm;
-  gal_data_t *tile_ll=(gal_data_t *)(tprm->params);
-
-  size_t i;
-  gal_data_t *tile;
-
-  /* Check all the tiles given to this thread. */
-  for(i=0; tprm->indexs[i] != GAL_BLANK_SIZE_T; ++i)
-    {
-      tile=&tile_ll[ tprm->indexs[i] ];
-      if( gal_blank_present(tile, 0) )
-        tile->flag |= GAL_DATA_FLAG_HASBLANK;
-    }
-
-  /* Wait for all the other threads to finish. */
-  if(tprm->b) pthread_barrier_wait(tprm->b);
-  return NULL;
-}
-
-
-
-
-
-/* Update the blank flag on the tiles within the list of input tiles. */
-void
-gal_tile_full_blank_flag(gal_data_t *tile_ll, size_t numthreads)
-{
-  /* Go over all the tiles and update their blank flag. */
-  gal_threads_spin_off(tile_full_blank_flag, tile_ll,
-                       gal_list_data_number(tile_ll), numthreads);
-}
-
-
-
-
 
 /* Clean up the allocated spaces in the parameters. */
 void



reply via email to

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