gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 9256566: Updating doc, lib. check as scripts,


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 9256566: Updating doc, lib. check as scripts, and lib. cleanup
Date: Tue, 25 Apr 2017 22:16:50 -0400 (EDT)

branch: master
commit 92565665db09d542b19a7f1acb0edabaf000f683
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Updating doc, lib. check as scripts, and lib. cleanup
    
    This work started with updating the documentation and in particular
    starting to describe `gal_data_t'. As it progressed, several corrections
    were made in the code and checks that are listed below. The documentation
    work is not complete, but these changes are large enough to warrant a
    commit.
    
     - The library chapter of the book now has a "Library demo programs"
       section that will have some simple programs to help users get started
       with the libraries.
    
     - The two functions `gal_data_alloc_number' and
       `gal_data_string_fixed_alloc_size' were not used anywhere in Gnuastro
       and not very generic, so they were removed. The one usage of the first
       (in `gal_data_string_to_number') was replaced with an `mmap' call and
       the second was moved into `lib/fits.c' as a static function.
    
     - To be more clear (mainly motivated by the book), the first argument to
       `gal_data_array_free' was changed to `dataarr' (previously it was just
       `data').
    
     - The library `multithread' check, now reads one of the images created
       during `make check' and prints its values by multiple threads thus both
       testing the reading of data into memory and the multithreaded
       features. This new re-write now also uses the new high-level
       `gal_threads_spin_off' function instead of the direct low-level usage of
       pthreads libraries.
    
     - Until now the actual library executable was tested (`check_PROGRAMS' was
       one of the values in `TESTS' in `Makefile.am'). This would cause
       problems when we wanted the library tests to depend on other tests: the
       tests creating the dependencies would be run multiple times. So after
       reviewing the "Scripts based testsuites", I noticed that we should
       actually also build scripts to run the `check_PROGRAMS'
       executables. This will allow them to also have their dependencies. So
       the two `lib/versioncpp.sh' and `lib/multithread.sh' scripts were
       created and are now in charge of testing the executables that are built.
---
 doc/gnuastro.texi        | 547 ++++++++++++++++++++++++++++++++++++++++++-----
 lib/data.c               | 133 ++----------
 lib/fits.c               |  54 ++++-
 lib/gnuastro/data.h      |  23 +-
 lib/threads.c            |   2 +-
 tests/Makefile.am        |  26 ++-
 tests/lib/multithread.c  | 160 ++++++--------
 tests/lib/multithread.sh |  48 +++++
 tests/lib/versioncpp.sh  |  45 ++++
 tests/prepconf.sh        |  36 ++--
 10 files changed, 762 insertions(+), 312 deletions(-)

diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index f0286df..5273526 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -516,6 +516,7 @@ Libraries
 
 * Review of library fundamentals::  Guide on libraries and linking.
 * Gnuastro library::            Description of all library functions.
+* Library demo programs::
 
 Review of library fundamentals
 
@@ -529,7 +530,9 @@ Gnuastro library
 * Configuration information::   General information about library config.
 * Library data container::
 * Library data types::
+* Table input output::
 * Arithmetic on datasets::
+* Tessellation library::
 * Bounding box::                Finding the bounding box.
 * FITS files::                  Working with FITS data.
 * Text files::
@@ -543,7 +546,8 @@ Gnuastro library
 
 Data container (@file{data.h})
 
-* Data container type::
+* Generic data container::
+* Basic dataset functions::
 
 FITS files (@file{fits.h})
 
@@ -555,6 +559,10 @@ Multithreaded programming (@file{threads.h})
 * Implementation of pthread_barrier::  Some systems don't have pthread_barrier
 * Gnuastro's thread related functions::  Functions for managing threads.
 
+Library demo programs
+
+* Library demo - reading a image::
+
 Developing
 
 * Why C::                       Why Gnuastro is designed in C.
@@ -15846,6 +15854,7 @@ program} to easily define your own programs(s).
 @menu
 * Review of library fundamentals::  Guide on libraries and linking.
 * Gnuastro library::            Description of all library functions.
+* Library demo programs::
 @end menu
 
 @node Review of library fundamentals, Gnuastro library, Libraries, Libraries
@@ -16475,7 +16484,7 @@ $ gnuastro-gcc myprog && ./myprog
 @end example
 
 
address@hidden Gnuastro library,  , Review of library fundamentals, Libraries
address@hidden Gnuastro library, Library demo programs, Review of library 
fundamentals, Libraries
 @section Gnuastro library
 
 Gnuastro library's programming constructs (function declarations, macros,
@@ -16530,7 +16539,9 @@ documentation will correspond to your installed version.
 * Configuration information::   General information about library config.
 * Library data container::
 * Library data types::
+* Table input output::
 * Arithmetic on datasets::
+* Tessellation library::
 * Bounding box::                Finding the bounding box.
 * FITS files::                  Working with FITS data.
 * Text files::
@@ -16640,22 +16651,23 @@ mask images are integers using bit-wise flags to 
identify certain classes
 of special pixels, see @ref{Numeric data types}). Certain other information
 about a dataset are also commonly necessary, for example the units of the
 dataset, the name of the dataset and some comments. To deal with any
-generic dataset, Gnuastro defines the @code{gal_data_t} type.
+generic dataset, Gnuastro defines the @code{gal_data_t} as input or output.
 
 @menu
-* Data container type::
+* Generic data container::
+* Basic dataset functions::
 @end menu
 
address@hidden Data container type,  , Library data container, Library data 
container
address@hidden Data container type (@code{gal_data_t})
address@hidden Generic data container, Basic dataset functions, Library data 
container, Library data container
address@hidden Generic data container (@code{gal_data_t})
 
-For a generic operation on any dataset (with various dimensions, numeric
-data types, units and higher-level structures), Gnuastro defines the
address@hidden type which is the main input/output of many Gnuastro's
-library functions. It is defined in @file{gnuastro/data.h}. If you will be
-using (address@hidden include}'ing) those libraries, you don't need to include
-this header explicity, it is already included by any library header that
-uses @code{gal_data_t}.
+To be able to deal with any dataset (various dimensions, numeric data
+types, units and higher-level structures), Gnuastro defines the
address@hidden type which is the input/output container of choice for
+many of Gnuastro library's functions. It is defined in
address@hidden/data.h}. If you will be using (address@hidden include}'ing) those
+libraries, you don't need to include this header explicity, it is already
+included by any library header that uses @code{gal_data_t}.
 
 @deftp {Type (C @code{struct})} gal_data_t
 The main container for datasets in Gnuastro. It can host data of any
@@ -16697,71 +16709,426 @@ typedef struct gal_data_t
 @noindent
 The list below contains a description for each @code{gal_data_t} element.
 
address@hidden @code{void *}
 @table @code
 @item void *restrict array
 This is the pointer to the main array of the dataset containing the raw
 data (values). All the other elements in this data-structure are actually
 meta-data enabling us to use/understand the series of values in this
-array. Since it is to use data of any type, the array is actually a
address@hidden *} pointer. A @code{void *} array is not directly usable, you
-can use a procedure like the example below to use the array in any
-type. You can compile and run this program with the script described in
address@hidden linking script}
+array. It must allow data of any type (see @ref{Numeric data types}), so it
+is defined as a @code{void *} pointer. A @code{void *} array is not
+directly usable in C, so you have to cast it to proper type before using
+it, please see @ref{Library demo - reading a image} for a demonstration.
+
address@hidden @code{restrict}
address@hidden C: @code{restrict}
+The @code{restrict} keyword was formally introduced in C99 and is used to
+tell the compiler that at any moment only this pointer will modify what it
+points to (the a pixel in an image for example)@footnote{Also see
address@hidden://en.wikipedia.org/wiki/Restrict}.}. This extra piece of
+information can greatly help in compiler optimizations and thus the running
+time of the program. But older compilers might not have this capability, so
+at @command{./configure} time, Gnuastro checks this feature and if the
+user's compiler doesn't support @code{restrict}, it will be removed from
+this definition.
+
address@hidden Data type
address@hidden uint8_t type
+A fixed code (integer) used to identify the type of data in @code{array}
+(see @ref{Numeric data types}). For the list of acceptable values to this
+variable, please see @ref{Library data types}.
+
address@hidden size_t ndim
+The dataset's number of dimensions.
+
+
address@hidden Fortran
address@hidden FITS standard
address@hidden Standard, FITS
address@hidden size_t *dsize
+The size of the dataset along each dimension. This is an array (with
address@hidden elements), of positive integers in row-major
address@hidden see
address@hidden://en.wikipedia.org/wiki/Row-_and_column-major_order}.}  (based
+on C). When a data file is read into memory with Gnuastro's libraries, this
+array is dynamically allocated based on the number of dimensions that the
+dataset has.
+
+It is important to remember that C's row-major ordering is the opposite of
+the FITS standard which is in column-major order: in the FITS standard the
+fastest dimension's size is specified by @code{NAXIS1}, and slower
+dimensions follow. The FITS standard was defined mainly based on the
+Fortran language which is the opposite of C's approach to multi-dimensional
+arrays (and also starts counting from 1 not 0). Hence if a FITS image has
address@hidden and @code{NAXIS2==50}, the @code{dsize} array must be
+filled with @code{dsize[0]==50} and @code{dsize[1]==20}.
+
+The fastest dimension is the one that is contiguous in memory: to increment
+by one along that dimension, just go to the next element in the array. As
+we go to slower dimensions, the number of memory cells we have to skip for
+an increment along that dimension becomes larger.
+
address@hidden size_t size
+The total number of elements in the dataset. This is actually a
+multiplication of all the values in the @code{dsize} array, so it is not an
+indepenent parameter. However, low-level operations with the dataset
+(irrespective of its dimensionality) commonly need this number, so this
+element is designed to avoid calculating it everytime.
+
address@hidden char *mmapname
+Name of file hosting the @code{mmap}'d contents of @code{array}. If the
+value of this variable is @code{NULL}, then the contents of @code{array}
+are actually stored in RAM, not in a file on the HDD/SSD. See the
+description of @code{minmapsize} below for more.
+
+If a file is used, it will be kept in the hidden @file{.gnuastro} directory
+with a randomly selected name to allow multiple arrays to be kept there at
+the same time. When @code{gal_data_free} is called the randomly named file
+will be deleted.
+
address@hidden size_t minmapsize
+The minimum size of an array (in bytes) to store the contents of
address@hidden as a file (on the non-volatile HDD/SSD), not in RAM. This can
+be very useful for large datasets which can be very memory intensive and
+the user's hardware RAM might not be sufficent to keep/process it. A random
+filename is assigned to the array which is available in the @code{mmapname}
+element of @code{gal_data_t} (above), see there for more.
+
+When this variable has a value of @code{0} (zero), any allocated
address@hidden will actually be in a file (not in RAM). When the value is
address@hidden (largest possible number in the unsigned types including
address@hidden) the array will be definitely allocated in RAM.
+
+Please note that using a non-volatile file instead of RAM will
+significantly increase the programs running time, especially on HDDs. So it
+is best to give this option very large values (depending on how much memory
+you will need for a given input). For example your processing might involve
+a copy of the the input (possibly to a wider data type which takes more
+bytes for each element), so take all such issues into
+consideration. @code{minmapsize} is actually stored in each
address@hidden, so it can be passed on to derivate datasets.
+
address@hidden nwcs
+The number of WCS coordinate representations (for WCSLIB).
+
address@hidden struct wcsprm *wcs
+The main WCSLIB structure keeping all the relevant information necessary
+for WCSLIB to do its processing and convert data-set positions into
+real-world positions. When it is given a @code{NULL} value, all posssible
+WCS calculations/measurements will be ignored.
+
address@hidden uint8_t flag
+Bit-wise flags to describe general properties of the dataset. The number of
+bytes available in this flag is stored in the @code{GAL_DATA_FLAG_SIZE}
+macro. Note that you should use bit-wise address@hidden
address@hidden://en.wikipedia.org/wiki/Bitwise_operations_in_C}.} to check
+these flags. The currently recognized bits are stored in these macros:
+
address@hidden @code
+
address@hidden Blank data
address@hidden GAL_DATA_FLAG_BLANK_CH
+Marking that the dataset has been checked for blank values. Therefore, the
+value of the bit in @code{GAL_DATA_FLAG_HASBLANK} is relibable. Without
+this bit, when a dataset doesn't have any blank values (and this has been
+checked), the @code{GAL_DATA_FLAG_HASBLANK} bit will be zero so a checker
+has no way to know if this zero is real or if no check has been done yet.
+
address@hidden GAL_DATA_FLAG_HASBLANK
+This bit has a value of @code{1} when the given dataset has blank
+values. If this bit is @code{0} and @code{GAL_DATA_FLAG_BLANK_CH} is
address@hidden, then the dataset has been checked and it didn't have any blank
+values, so there is no more need for further checks.
+
address@hidden GAL_DATA_FLAG_SORT_CH
+Marking that the dataset is already checked for being sorted or not and
+thus that the possible @code{0} values in @code{GAL_DATA_FLAG_SORTED_I} and
address@hidden are meaningful.
+
address@hidden GAL_DATA_FLAG_SORTED_I
+This bit has a value of @code{1} when the given dataset is sorted in an
+increasing manner. If this bit is @code{0} and @code{GAL_DATA_FLAG_SORT_CH}
+is @code{1}, then the dataset has been checked and wasn't sorted
+(increasing), so there is no more need for further checks.
+
address@hidden GAL_DATA_FLAG_SORTED_D
+This bit has a value of @code{1} when the given dataset is sorted in a
+decreasing manner. If this bit is @code{0} and @code{GAL_DATA_FLAG_SORT_CH}
+is @code{1}, then the dataset has been checked and wasn't sorted
+(decreasing), so there is no more need for further checks.
 
address@hidden table
+
+The macro @code{GAL_DATA_FLAG_MAXFLAG} contains the largest internally used
+bit-position. Higher-level flags can be defined with the bit-wise shift
+operators using this macro to define internal flags for libraries/programs
+that depend on Gnuastro without causing any possible conflict with the
+internal flags discussed above or having to check the values manually on
+every release.
+
+
address@hidden int status
+A context-specific status values for this data-structure. This integer will
+not be set by Gnuastro's libraries. You can use it keep some additional
+information about the dataset (with integer constants) depending on your
+applications.
+
address@hidden char *name
+The name of the dataset. If the dataset is a multi-dimensional array and
+read/written as a FITS image, this will be the value in the @code{EXTNAME}
+FITS keyword. If the dataset is a one-dimensional table column, this will
+be the column name. If it is set to @code{NULL} (by default), it will be
+ignored.
+
address@hidden char *unit
+The units of the dataset (for example @code{BUNIT} in the standard FITS
+keywords) that will be read from or written to files/tables along with the
+dataset. If it is set to @code{NULL} (by default), it will be ignored.
+
address@hidden char *comment
+Any further explanation about the dataset which will be written to any
+output file if present.
+
address@hidden disp_fmt
+Format to use for printing each element of the dataset to a plain text
+file, the acceptable values to this element are defined in @ref{Table input
+output}. Based on C's @code{printf} standards.
+
address@hidden disp_width
+Width of printing each element of the dataset to a plain text file, the
+acceptable values to this element are defined in @ref{Table input
+output}. Based on C's @code{printf} standards.
+
address@hidden disp_precision
+Width of printing each element of the dataset to a plain text file, the
+acceptable values to this element are defined in @ref{Table input
+output}. Based on C's @code{printf} standards.
+
address@hidden gal_data_t *next
+Through this pointer, you can link a @code{gal_data_t} with other datasets
+related datasets, for example the different columns in a dataset each have
+one @code{gal_data_t} associate with them and they are linked to each other
+using this element. There are several functions described below to
+facilitate using @code{gal_data_t} as a linked list. See @ref{Linked lists}
+for more on these wonderful high-level constructs.
+
address@hidden gal_data_t *block
+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.
 
 @example
-#include <stdio.h>
-#include <stdlib.h>
-#include <gnuastro/fits.h>
-#include <gnuastro/statistics.h>
+                            larger
+              ---------------------------------
+              |                               |
+              |              tile             |
+              |           ----------          |
+              |           |        |          |
+              |           |_       |          |
+              |           |*|      |          |
+              |           ----------          |
+              |       tile->block = larger    |
+              |_                              |
+              |*|                             |
+              ---------------------------------
address@hidden example
 
-int
-main(void)
address@hidden
-  size_t i;
-  float *farray;
-  double sum=0.0f;
-  gal_data_t *image;
-  char *filename="img.fits", *hdu="1";
+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.
 
-  /* Read `img.fits' (HDU: 1) as a float32 array. */
-  image=gal_fits_img_read_to_type(filename, hdu,
-                                  GAL_TYPE_FLOAT32, -1);
address@hidden table
 
-  /* Use the allocated space as a single precision floating
-   * point array (recall that `image->array' has `void *'
-   * type, so it is not directly usable. */
-  farray=image->array;
 
-  /* Calculate the sum of all the values. */
-  for(i=0; i<image->size; ++i)
-    sum += farray[i];
address@hidden Basic dataset functions,  , Generic data container, Library data 
container
address@hidden Basic dataset functions
 
-  /* Report the sum. */
-  printf("Sum of values in %s (hdu %s) is: %f\n",
-         filename, hdu, sum);
+Gnuastro's main data container was defined in @ref{Generic data container},
+the functions listed in this section describe the most basic operations on
address@hidden, operations related to the size, allocation,
+initializations, copying, changing types and etc. The first class of
+functions discussed below are for size, allocation and initialization.
 
-  /* Clean up and return. */
-  gal_data_free(image);
-  return EXIT_SUCCESS;
address@hidden
address@hidden example
address@hidden int gal_data_dsize_is_different (gal_data_t @code{*first}, 
gal_data_t @code{*second})
+Return @code{1} (one) if the two datasets don't have the same size along
+all dimensions. This function will also return @code{1} when the number of
+dimensions of the two datasets are different.
address@hidden deftypefun
 
address@hidden table
address@hidden {void *} gal_data_ptr_increment (void @code{*pointer}, size_t 
@code{increment}, uint8_t @code{type})
+Return a pointer to an element that is @code{increment} elements ahead of
address@hidden, assuming each element has type of @code{type} (for the type
+codes, see @ref{Library data types}).
+
+When working with the @code{array} elements of @code{gal_data_t}, we are
+actually dealing with @code{void *} pointers. However, pointer arithmetic
+doesn't apply to @code{void *}, because the system doesn't know how many
+bytes there are in each element to increment the pointer respectively. This
+function will use the given @code{type} to calculate where the incremented
+element is located in memory.
address@hidden deftypefun
+
address@hidden size_t gal_data_ptr_dist (void @code{*earlier}, void 
@code{*later}, uint8_t @code{type})
+Return the number of elements between @code{earlier} and @code{later}
+assuming each element has a type defined by @code{type} (for the type
+codes, see @ref{Library data types}).
address@hidden deftypefun
+
address@hidden {void *} gal_data_malloc_array (uint8_t @code{type}, size_t 
@code{size})
+Allocate an array of type @code{type} with @code{size} elements in RAM (for
+the type codes, see @ref{Library data types}). This is effectively just a
+wrapper around C's @code{malloc} function but takes Gnuastro's integer type
+codes and will also abort with an error if there the allocation was not
+successful.
address@hidden deftypefun
+
address@hidden {void *} gal_data_calloc_array (uint8_t @code{type}, size_t 
@code{size})
+Allocate and clear (initialize to zero) an array of type @code{type} with
address@hidden elements in RAM (for the type codes, see @ref{Library data
+types}). This is effectively just a wrapper around C's @code{calloc}
+function but takes Gnuastro's integer type codes and will also abort with
+an error if there the allocation was not successful.
address@hidden deftypefun
+
address@hidden void gal_data_initialize (gal_data_t @code{*data}, void 
@code{*array}, uint8_t @code{type}, size_t @code{ndim}, size_t @code{*dsize}, 
struct wcsprm @code{*wcs}, int @code{clear}, size_t @code{minmapsize}, char 
@code{*name}, char @code{*unit}, char @code{*comment})
+
+Initialize the given data structure (@code{data}) with all the given
+values. Note that the raw input @code{gal_data_t} must already have been
+allocated before calling this function. For a description of each variable
+see @ref{Generic data container}. It will set the values and do the
+necessary allocations. If they aren't @code{NULL}, all input arrays
+(@code{dsize}, @code{wcs}, @code{name}, @code{unit}, @code{comment}) are
+separately copied (allocated) by this function for usage in @code{data}, so
+you can safely use one value to initialize many datasets or use statically
+allocated variables in this function call. Once you are done with the
+dataset, you can clean all the allocated spaces with
address@hidden
+
+If @code{array} is not @code{NULL}, it will be directly copied into
address@hidden>array} and no new space will be allocated for the array of this
+dataset, this has many low-level advantages and can be used to work on
+regions of a dataset instead of the whole allocated array (see the
+description under @code{block} in @ref{Generic data container} for one
+example). If the given pointer is not the start of an allocated block of
+memory or it is used in multiple datasets, be sure to set it to @code{NULL}
+(with @code{data->array=NULL}) before cleaning up with
address@hidden
address@hidden deftypefun
+
address@hidden {void *} gal_data_alloc (void @code{*array}, uint8_t 
@code{type}, size_t @code{ndim}, size_t @code{*dsize}, struct wcsprm 
@code{*wcs}, int @code{clear}, size_t @code{minmapsize}, char @code{*name}, 
char @code{*unit}, char @code{*comment})
+
+Dynamically allocate a @code{gal_data_t} and initialize it will all the
+given values. See the description of @code{gal_data_initialize} and
address@hidden data container} for more information. This function will often
+be the most frequently used because it allocates the @code{gal_data_t}
+hosting all the values @emph{and} initializes it. Once you are done with
+the dataset, be sure to clean up all the allocated spaces with
address@hidden
address@hidden deftypefun
+
address@hidden void gal_data_free_contents (gal_data_t @code{*data})
+Free all the address@hidden pointers in @code{gal_data_t}, for a complete
+description of the @code{gal_data_t} contents, see @ref{Generic data
+container}.
address@hidden deftypefun
+
address@hidden void gal_data_free (gal_data_t @code{*data})
+Free all the address@hidden pointers in @code{gal_data_t}, then free the
+actual data structure.
address@hidden deftypefun
+
address@hidden is a very versatile structure that can be used in many
+higher-level contexts. For example you can have an array of
address@hidden structures when several @code{gal_data_t}s are
+related. The functions below are defined to create a cleared array of data
+structures and to free them.
 
address@hidden {gal_data_t *} gal_data_array_calloc (size_t @code{size})
+Allocate an array of @code{gal_data_t} with @code{size} elements. This
+function will also initialize all the values (@code{NULL} for pointers and
+0 for other types). You can use @code{gal_data_initialize} to fill each
+element of the array. The following code snippet is one example of using
+arrays of @code{gal_data_t}.
 
address@hidden
+size_t i;
+gal_data_t *dataarr;
+dataarr=gal_data_array_calloc(10);
+for(i=0;i<10;++i) gal_data_initialize(&dataarr[i], ...);
+...
+gal_data_array_free(dataarr, 10, 1);
address@hidden example
address@hidden deftypefun
 
address@hidden Library data types, Arithmetic on datasets, Library data 
container, Gnuastro library
address@hidden void gal_data_array_free (gal_data_t @code{*dataarr}, size_t 
@code{num}, int @code{free_array})
+Free all the @code{num} elements within @code{dataarr} and the actual
+allocated array. If @code{free_array} is not zero, then the @code{array}
+element of all the datasets will also be freed, see @ref{Generic data
+container}.
address@hidden deftypefun
+
address@hidden Library data types, Table input output, Library data container, 
Gnuastro library
 @subsection Library data types (@file{type.h})
 
 This header defines basic type identifiers and functions relating to the
 different types.
 
address@hidden Arithmetic on datasets, Bounding box, Library data types, 
Gnuastro library
address@hidden Table input output, Arithmetic on datasets, Library data types, 
Gnuastro library
address@hidden Table input output (@file{table.h})
+
+Functions to read columns from/to tables.
+
address@hidden Arithmetic on datasets, Tessellation library, Table input 
output, Gnuastro library
 @subsection Arithmetic on datasets (@file{arithmetic.h})
 
address@hidden Tessellation library, Bounding box, Arithmetic on datasets, 
Gnuastro library
address@hidden Tessellation library (@file{tile.h})
 
address@hidden Bounding box, FITS files, Arithmetic on datasets, Gnuastro 
library
+
address@hidden Bounding box, FITS files, Tessellation library, Gnuastro library
 @subsection Bounding box (@file{box.h})
 
 Functions related to reporting a the bounding box of certain inputs are
@@ -18222,6 +18589,82 @@ Given the WCS structure @code{wcs} calculate the pixel 
area in
 arcsec-squared.
 @end deftypefun
 
address@hidden Library demo programs,  , Gnuastro library, Libraries
address@hidden Library demo programs
+
+In this final section of @ref{Libraries}, we give some example Gnuastro
+programs to demonstrate various features in the library. All these programs
+have been tested and once Gnuastro is installed you can compile and run
+them with with the program-like shell function that is described in
address@hidden linking script}. If you don't have any FITS file to
+experiment on, you can use those that are generated by Gnuastro after
address@hidden check} in the @file{tests/} directory, see @ref{Quick start}.
+
+
address@hidden
+* Library demo - reading a image::
address@hidden menu
+
address@hidden Library demo - reading a image,  , Library demo programs, 
Library demo programs
address@hidden Library demo - reading a FITS image
+
+The following simple program demonstrates how to read a FITS image into
+memory and use the @code{void *array} pointer in of @ref{Generic data
+container}. For easy linking/compilation of this program along with a first
+run see @ref{Automatic linking script}. Before running, also change the
address@hidden and @code{hdu} variable values to specify an existing FITS
+file and/or extension/HDU.
+
+This is just intended to demonstrate how to use the @code{array} pointer of
address@hidden Hence it doesn't do important sanity checks, for example
+in real datasets you may also have blank pixels. In such cases, this
+program will return a NaN value (see @ref{Blank pixels}). So for general
+statistical information of a dataset, it is much better to use Gnuastro's
address@hidden program which can deal with blank pixels any many other
+issues in a generic dataset.
+
address@hidden
+#include <stdio.h>
+#include <stdlib.h>
+#include <gnuastro/fits.h> /* includes gnuastro's data.h and type.h */
+#include <gnuastro/statistics.h>
+
+int
+main(void)
address@hidden
+  size_t i;
+  float *farray;
+  double sum=0.0f;
+  gal_data_t *image;
+  char *filename="img.fits", *hdu="1";
+
+
+  /* Read `img.fits' (HDU: 1) as a float32 array. */
+  image=gal_fits_img_read_to_type(filename, hdu, GAL_TYPE_FLOAT32, -1);
+
+
+  /* Use the allocated space as a single precision floating
+   * point array (recall that `image->array' has `void *'
+   * type, so it is not directly usable. */
+  farray=image->array;
+
+
+  /* Calculate the sum of all the values. */
+  for(i=0; i<image->size; ++i)
+    sum += farray[i];
+
+
+  /* Report the sum. */
+  printf("Sum of values in %s (hdu %s) is: %f\n",
+         filename, hdu, sum);
+
+
+  /* Clean up and return. */
+  gal_data_free(image);
+  return EXIT_SUCCESS;
address@hidden
address@hidden example
+
 
 
 
diff --git a/lib/data.c b/lib/data.c
index 1b7d766..7795152 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -162,62 +162,6 @@ gal_data_calloc_array(uint8_t type, size_t size)
 
 
 
-/* Allocate space for one blank value of the given type and put the value
-   in it. */
-void *
-gal_data_alloc_number(uint8_t type, void *number)
-{
-  void *allocd;
-
-  /* Allocate the space for the blank value: */
-  allocd=gal_data_malloc_array(type, 1);
-
-  /* Put the blank value into it. */
-  errno=0;
-  switch(type)
-    {
-    case GAL_TYPE_BIT:
-      error(EXIT_FAILURE, 0, "Currently Gnuastro doesn't support blank "
-            "values for `GAL_TYPE_BIT', please get in touch with "
-            "us to see how we can implement it.");
-
-    case GAL_TYPE_UINT8:   *(uint8_t *)allocd  = *(uint8_t *)  number; break;
-    case GAL_TYPE_INT8:    *(int8_t *)allocd   = *(int8_t *)   number; break;
-    case GAL_TYPE_UINT16:  *(uint16_t *)allocd = *(uint16_t *) number; break;
-    case GAL_TYPE_INT16:   *(int16_t *)allocd  = *(int16_t *)  number; break;
-    case GAL_TYPE_UINT32:  *(uint32_t *)allocd = *(uint32_t *) number; break;
-    case GAL_TYPE_INT32:   *(int32_t *)allocd  = *(int32_t *)  number; break;
-    case GAL_TYPE_UINT64:  *(uint64_t *)allocd = *(uint64_t *) number; break;
-    case GAL_TYPE_INT64:   *(int64_t *)allocd  = *(int64_t *)  number; break;
-    case GAL_TYPE_FLOAT32: *(float *)allocd    = *(float *)    number; break;
-    case GAL_TYPE_FLOAT64: *(double *)allocd   = *(double *)   number; break;
-
-    case GAL_TYPE_COMPLEX32:
-      GSL_COMPLEX_P_REAL(((gsl_complex_float *)allocd)) =
-        GSL_COMPLEX_P_REAL(((gsl_complex_float *)number));
-      GSL_COMPLEX_P_IMAG(((gsl_complex_float *)allocd)) =
-        GSL_COMPLEX_P_IMAG(((gsl_complex_float *)number));
-      break;
-
-    case GAL_TYPE_COMPLEX64:
-      GSL_COMPLEX_P_REAL(((gsl_complex *)allocd)) =
-        GSL_COMPLEX_P_REAL(((gsl_complex *)number));
-      GSL_COMPLEX_P_IMAG(((gsl_complex *)allocd)) =
-        GSL_COMPLEX_P_IMAG(((gsl_complex *)number));
-      break;
-
-    default:
-      error(EXIT_FAILURE, 0, "type value of %d not recognized in "
-            "`gal_data_alloc_number'", type);
-    }
-
-  return allocd;
-}
-
-
-
-
-
 static void
 gal_data_mmap(gal_data_t *data, int clear)
 {
@@ -413,60 +357,6 @@ gal_data_alloc(void *array, uint8_t type, size_t ndim, 
size_t *dsize,
 
 
 
-/* In some contexts, it is necessary for all the strings to have the same
-   allocated space (when the `strlen' is different). This function will
-   allocate new copies for all elements to have the same length as the
-   maximum length and set all trailing elements to `\0' for those that are
-   shorter than the length. The return value is the allocated space. If the
-   dataset is not a string, the returned value will be -1 (largest number
-   of `size_t'). */
-size_t
-gal_data_string_fixed_alloc_size(gal_data_t *data)
-{
-  size_t i, j, maxlen=0;
-  char *tmp, **strarr=data->array;
-
-  /* Return 0 if the dataset is not a string. */
-  if(data->type!=GAL_TYPE_STRING)
-    return -1;
-
-  /* Get the maximum length. */
-  for(i=0;i<data->size;++i)
-    maxlen = strlen(strarr[i])>maxlen ? strlen(strarr[i]) : maxlen;
-
-  /* For all elements, check the length and if they aren't equal to maxlen,
-     then allocate a maxlen sized array and put the values in. */
-  for(i=0;i<data->size;++i)
-    {
-      /* Allocate (and clear) the space for the new string. We want it to
-         be cleared, so when the strings are smaller, the rest of the space
-         is filled with '\0' (ASCII for 0) values.*/
-      errno=0;
-      tmp=calloc(maxlen+1, sizeof *strarr[i]);
-      if(tmp==NULL)
-        error(EXIT_FAILURE, 0, "%zu bytes for tmp in "
-              "`gal_data_fixed_alloc_size_for_string'",
-              maxlen+1*sizeof *strarr[i]);
-
-      /* Put the old array into the newly allocated space. `tmp' was
-         cleared (all values set to `\0', so we don't need to set the final
-         one explicity after the copy.*/
-      for(j=0;strarr[i][j]!='\0';++j)
-        tmp[j]=strarr[i][j];
-
-      /* Free the old array and put in the new one. */
-      free(strarr[i]);
-      strarr[i]=tmp;
-    }
-
-  /* Return the allocated space. */
-  return maxlen+1;
-}
-
-
-
-
-
 /* Free the allocated contents of a data structure, not the structure
    itsself. The reason that this function is separate from `gal_data_free'
    is that the data structure might be allocated as an array (statically
@@ -603,26 +493,26 @@ gal_data_array_calloc(size_t size)
 
 /* When you have an array of data structures. */
 void
-gal_data_array_free(gal_data_t *data, size_t size, int free_array)
+gal_data_array_free(gal_data_t *dataarr, size_t size, int free_array)
 {
   size_t i;
 
   /* If its NULL, don't do anything. */
-  if(data==NULL) return;
+  if(dataarr==NULL) return;
 
   /* First free all the contents. */
   for(i=0;i<size;++i)
     {
       /* See if the array should be freed or not. */
       if(free_array==0)
-        data[i].array=NULL;
+        dataarr[i].array=NULL;
 
       /* Now clear the contents of the dataset. */
-      gal_data_free_contents(&data[i]);
+      gal_data_free_contents(&dataarr[i]);
     }
 
   /* Now you can free the whole array. */
-  free(data);
+  free(dataarr);
 }
 
 
@@ -1363,10 +1253,11 @@ gal_data_write_to_string(void *ptr, uint8_t type, int 
quote_if_str_has_space)
 gal_data_t *
 gal_data_string_to_number(char *string)
 {
-  size_t dsize[1]={1};
+  void *ptr;
+  gal_data_t *out;
   int fnz=-1, lnz=0;     /* `F'irst (or `L'ast) `N'on-`Z'ero. */
-  void *ptr, *numarr;
   char *tailptr, *cp;
+  size_t dsize[1]={1};
   uint8_t type, forcedfloat=0;
 
   /* Define initial spaces to keep the value. */
@@ -1436,10 +1327,10 @@ gal_data_string_to_number(char *string)
         {      ptr=&d; type=GAL_TYPE_FLOAT64; }
     }
 
-  /* Return the pointer to the data structure. */
-  numarr=gal_data_alloc_number(type, ptr);
-  return gal_data_alloc(numarr, type, 1, dsize, NULL, 0, -1,
-                        NULL, NULL, NULL);
+  /* Allocate a one-element dataset, then copy the number into it. */
+  out=gal_data_alloc(NULL, type, 1, dsize, NULL, 0, -1, NULL, NULL, NULL);
+  memcpy(out->array, ptr, gal_type_sizeof(type));
+  return out;
 }
 
 
diff --git a/lib/fits.c b/lib/fits.c
index e3a56f4..31834a2 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -2099,6 +2099,58 @@ gal_fits_tab_read(char *filename, char *hdu, size_t 
numrows,
 
 
 
+/* This function will allocate new copies for all elements to have the same
+   length as the maximum length and set all trailing elements to `\0' for
+   those that are shorter than the length. The return value is the
+   allocated space. If the dataset is not a string, the returned value will
+   be -1 (largest number of `size_t'). */
+static size_t
+fits_string_fixed_alloc_size(gal_data_t *data)
+{
+  size_t i, j, maxlen=0;
+  char *tmp, **strarr=data->array;
+
+  /* Return 0 if the dataset is not a string. */
+  if(data->type!=GAL_TYPE_STRING)
+    return -1;
+
+  /* Get the maximum length. */
+  for(i=0;i<data->size;++i)
+    maxlen = strlen(strarr[i])>maxlen ? strlen(strarr[i]) : maxlen;
+
+  /* For all elements, check the length and if they aren't equal to maxlen,
+     then allocate a maxlen sized array and put the values in. */
+  for(i=0;i<data->size;++i)
+    {
+      /* Allocate (and clear) the space for the new string. We want it to
+         be cleared, so when the strings are smaller, the rest of the space
+         is filled with '\0' (ASCII for 0) values.*/
+      errno=0;
+      tmp=calloc(maxlen+1, sizeof *strarr[i]);
+      if(tmp==NULL)
+        error(EXIT_FAILURE, 0, "%zu bytes for tmp in "
+              "`gal_data_fixed_alloc_size_for_string'",
+              maxlen+1*sizeof *strarr[i]);
+
+      /* Put the old array into the newly allocated space. `tmp' was
+         cleared (all values set to `\0', so we don't need to set the final
+         one explicity after the copy.*/
+      for(j=0;strarr[i][j]!='\0';++j)
+        tmp[j]=strarr[i][j];
+
+      /* Free the old array and put in the new one. */
+      free(strarr[i]);
+      strarr[i]=tmp;
+    }
+
+  /* Return the allocated space. */
+  return maxlen+1;
+}
+
+
+
+
+
 static void
 fits_table_prepare_arrays(gal_data_t *cols, size_t numcols, int tabletype,
                           char ***outtform, char ***outttype,
@@ -2195,7 +2247,7 @@ fits_table_prepare_arrays(gal_data_t *cols, size_t 
numcols, int tabletype,
 
           /* If this is a string column, set all the strings to same size,
              then write the value of tform depending on the type. */
-          col->disp_width=gal_data_string_fixed_alloc_size(col);
+          col->disp_width=fits_string_fixed_alloc_size(col);
           fmt[0]=gal_fits_type_to_bin_tform(col->type);
           if( col->type==GAL_TYPE_STRING )
             asprintf(&tform[i], "%d%c", col->disp_width, fmt[0]);
diff --git a/lib/gnuastro/data.h b/lib/gnuastro/data.h
index 4b29476..205032a 100644
--- a/lib/gnuastro/data.h
+++ b/lib/gnuastro/data.h
@@ -72,10 +72,10 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 
 /* Number of bytes in the unsigned integer hosting the bit-flags (`flag'
    element) of `gal_data_t'. */
-#define GAL_DATA_FLAG_SIZE       1
+#define GAL_DATA_FLAG_SIZE         1
 
 /* Bit 0: The has-blank flag has been checked, so a flag value of 0 for the
-          blank flag is strustable. This can be very useful to avoid
+          blank flag is trustable. This can be very useful to avoid
           repetative checks when the necessary value of the bit is 0. */
 #define GAL_DATA_FLAG_BLANK_CH     0x1
 
@@ -91,10 +91,11 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 /* Bit 4: Dataset is sorted and decreasing. */
 #define GAL_DATA_FLAG_SORTED_D     0x10
 
-/*    Maximum internal flag value, using bitwise shift operators, this can
-      be used to define internal flags for libraries/programs that depend
-      on Gnuastro without causing any conflict with the internal flags or
-      having to check the values manually on every release. */
+/* Maximum internal flag value. Higher-level flags can be defined with the
+   bitwise shift operators on this value to define internal flags for
+   libraries/programs that depend on Gnuastro without causing any possible
+   conflict with the internal flags or having to check the values manually
+   on every release. */
 #define GAL_DATA_FLAG_MAXFLAG      GAL_DATA_FLAG_SORTED_D
 
 
@@ -197,7 +198,7 @@ typedef struct gal_data_t
 {
   /* Basic information on array of data. */
   void     *restrict array;  /* Array keeping data elements.               */
-  uint8_t             type;  /* Type of data (from `gal_data_alltypes').   */
+  uint8_t             type;  /* Type of data (see `gnuastro/type.h').      */
   size_t              ndim;  /* Number of dimensions in the array.         */
   size_t            *dsize;  /* Size of array along each dimension.        */
   size_t              size;  /* Total number of data-elements.             */
@@ -247,9 +248,6 @@ gal_data_malloc_array(uint8_t type, size_t size);
 void *
 gal_data_calloc_array(uint8_t type, size_t size);
 
-void *
-gal_data_alloc_number(uint8_t type, void *number);
-
 void
 gal_data_initialize(gal_data_t *data, void *array, uint8_t type, size_t ndim,
                     size_t *dsize, struct wcsprm *wcs, int clear,
@@ -260,9 +258,6 @@ gal_data_alloc(void *array, uint8_t type, size_t ndim, 
size_t *dsize,
                struct wcsprm *wcs, int clear, size_t minmapsize,
                char *name, char *unit, char *comment);
 
-size_t
-gal_data_string_fixed_alloc_size(gal_data_t *data);
-
 void
 gal_data_free_contents(gal_data_t *data);
 
@@ -280,7 +275,7 @@ gal_data_t *
 gal_data_array_calloc(size_t size);
 
 void
-gal_data_array_free(gal_data_t *data, size_t num, int free_array);
+gal_data_array_free(gal_data_t *dataarr, size_t num, int free_array);
 
 
 
diff --git a/lib/threads.c b/lib/threads.c
index b72a077..a4d99ef 100644
--- a/lib/threads.c
+++ b/lib/threads.c
@@ -274,7 +274,7 @@ gal_threads_attr_barrier_init(pthread_attr_t *attr, 
pthread_barrier_t *b,
        int    value1;
        double value2;
        float  *array;
-     }
+     };
 
 
      ---------    Function to run on each thread  ---------
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6b9a8c1..3d7db21 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -177,6 +177,7 @@ AM_CPPFLAGS = -I../lib
 
 # Environment variables for the test scripts.
 AM_TESTS_ENVIRONMENT =                              \
+export mkdir_p="$(MKDIR_P)";                        \
 export topsrc=$(top_srcdir);                        \
 export haslibjpeg=$(MAYBE_HASLIBJPEG);              \
 export hasghostscript=$(MAYBE_HASGHOSTSCRIPT);
@@ -185,21 +186,32 @@ export hasghostscript=$(MAYBE_HASGHOSTSCRIPT);
 
 
 
-# Compilations that are to be done with `make check'.
+# Library checks
+# ==============
+#
+# The Gnuastro library is checked by compiling programs and linking them
+# with the library. As described in the last paragraph of the "Scripts
+# based test suites" section of the Automake manual, all targets specified
+# by `check_PROGRAMS' are compiled prior to actually running the targets of
+# `TESTS'. So they do not need to be specified as any dependency, they will
+# be present when the `.sh' based tests are run.
 LDADD = -lgnuastro
 check_PROGRAMS = versioncpp multithread
 versioncpp_SOURCES = lib/versioncpp.cpp
 multithread_SOURCES = lib/multithread.c
+lib/multithread.sh: mkprof/mosaic1.sh.log
 
 
 
 
-# The actual test scripts that are run:
-TESTS = prepconf.sh $(check_PROGRAMS) $(MAYBE_ARITHMETIC_TESTS)                
   \
-  $(MAYBE_CONVERTT_TESTS) $(MAYBE_CONVOLVE_TESTS) $(MAYBE_COSMICCAL_TESTS) \
-  $(MAYBE_CROP_TESTS) $(MAYBE_FITS_TESTS) $(MAYBE_MKCATALOG_TESTS)        \
-  $(MAYBE_MKNOISE_TESTS) $(MAYBE_MKPROF_TESTS) $(MAYBE_NOISECHISEL_TESTS)  \
-  $(MAYBE_STATISTICS_TESTS) $(MAYBE_SUBTRACTSKY_TESTS)                    \
+# Final Tests
+# ===========
+TESTS = prepconf.sh lib/versioncpp.sh lib/multithread.sh                \
+  $(MAYBE_ARITHMETIC_TESTS) $(MAYBE_CONVERTT_TESTS)                     \
+  $(MAYBE_CONVOLVE_TESTS) $(MAYBE_COSMICCAL_TESTS) $(MAYBE_CROP_TESTS)  \
+  $(MAYBE_FITS_TESTS) $(MAYBE_MKCATALOG_TESTS) $(MAYBE_MKNOISE_TESTS)   \
+  $(MAYBE_MKPROF_TESTS) $(MAYBE_NOISECHISEL_TESTS)                      \
+  $(MAYBE_STATISTICS_TESTS) $(MAYBE_SUBTRACTSKY_TESTS)                  \
   $(MAYBE_TABLE_TESTS) $(MAYBE_WARP_TESTS)
 
 
diff --git a/tests/lib/multithread.c b/tests/lib/multithread.c
index 13f1b95..1043a41 100644
--- a/tests/lib/multithread.c
+++ b/tests/lib/multithread.c
@@ -4,7 +4,7 @@ A test program to multithreaded building using Gnuastro's 
helpers.
 Original author:
      Mohammad Akhlaghi <address@hidden>
 Contributing author(s):
-Copyright (C) 2016, 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
@@ -22,134 +22,102 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "gnuastro/fits.h"
 #include "gnuastro/threads.h"
 
 
-/* The params structure will keep the input information for each thread. As
-   you see below, we will actually be defining an array of these
-   structures, one for each thread. The reason for this is that the
-   function that spins off threads only passes one argument, so as that
-   argument, we will be passing the pointer to this structure. You can
-   easily add new elements to this structure to use in the threads
-   function. */
+/* This structure can keep all information you want to pass onto the worker
+   function on each thread. */
 struct params
 {
-  size_t            id; /* Id of this thread.                            */
-  size_t       *indexs; /* Indexes of actions to be done in this thread. */
-  pthread_barrier_t *b; /* Pointer the barrier for all threads.          */
+  gal_data_t *image;            /* Dataset to print values of. */
 };
 
 
 
 
-
-/* Worker function on threads */
+/* This is the main worker function which will be called by the different
+   threads. `gal_threads_params' is defined in `gnuastro/threads.h' and
+   contains the pointer to the paramter we want. Note that its input and
+   output must have `void *' types. */
 void *
-worker(void *inparam)
+worker_on_thread(void *in_prm)
 {
-  /* The first thing to do is to say what the input pointer actually is. */
-  struct params *prm=(struct params*)inparam;
+  /* Low-level definitions to be done first. */
+  struct gal_threads_params *tprm=(struct gal_threads_params *)in_prm;
+  struct params *p=(struct params *)tprm->params;
+
+
+  /* Subsequent definitions. */
+  float *array=p->image->array;
+  size_t i, index, *dsize=p->image->dsize;
 
-  /* Now you can go onto do defining the function like any other
-     function: first you define the variables and so on... */
-  size_t i;
 
-  /* Go over the jobs indexed for this thread: */
-  for(i=0; prm->indexs[i] != GAL_BLANK_SIZE_T; ++i)
+  /* Go over all the pixels that were assigned to this thread. */
+  for(i=0; tprm->indexs[i] != GAL_BLANK_SIZE_T; ++i)
     {
-      /* The indexes of the actions will make it possible to point to
-         whatever data structure or input you want. So in this test, we
-         will just print the thread ID and action id. */
-      printf("thread %zu: %zu\n", prm->id, prm->indexs[i]);
+      /* For easy reading. */
+      index = tprm->indexs[i];
+
+
+      /* Print the information. */
+      printf("(%zu, %zu) on thread %zu: %g\n", index%dsize[1]+1,
+             index/dsize[1]+1, tprm->id, array[index]);
     }
 
-  /* Wait until all other threads finish. When there was only one thread,
-     we explicitly set the pointer to the barrier structure to NULL, so
-     only wait when a barrier is actually defined.*/
-  if(prm->b)
-    pthread_barrier_wait(prm->b);
 
-  /* Return the NULL pointer. */
+  /* Wait for all the other threads to finish, then return. */
+  if(tprm->b) pthread_barrier_wait(tprm->b);
   return NULL;
 }
 
 
 
 
-/* This is the thread spinner function. */
+/* A simple program to open a FITS image, distributes its pixels between
+   different threads and print the value of each pixel and the thread it
+   was assigned to, this will test both the opening of a FITS file and also
+   the multi-threaded functions. After running `make check' you can see the
+   outputs in `tests/multithread.log'.
+
+   Please run the following command for an explanation on easily linking
+   and compiling C programs that use Gnuastro's libraries (without having
+   to worry about the libraries to link to) anywhere on your system:
+
+      $ info gnuastro "Automatic linking script"
+*/
 int
 main(void)
 {
-  int err;
-  pthread_t t;          /* All thread ids saved in this, not used. */
-  struct params *prm;
-  size_t numbarriers;
-  pthread_attr_t attr;
-  pthread_barrier_t b;
-  size_t i, *indexs, thrdcols;
-  size_t numthreads=8, numactions=1000;
-
-  /* Allocate the array of `param' structures. Note that in most cases, the
-     number of threads will not be a constant like this simple case, it
-     will be a variable passed to the thread-spinner. So we are using
-     dynamic allocation for more general use as a tutorial. */
-  prm=malloc(numthreads*sizeof *prm);
-  if(prm==NULL)
+  struct params p;
+  char *filename="psf.fits", *hdu="1";
+  size_t numthreads=gal_threads_number();
+
+
+  /* Read the image into memory as a float32 data type. */
+  p.image=gal_fits_img_read_to_type(filename, hdu, GAL_TYPE_FLOAT32, -1);
+
+
+  /* Print some basic information before the actual contents: */
+  printf("Pixel values of %s (HDU: %s) on %zu threads.\n", filename, hdu,
+         numthreads);
+  printf("Used to check the compiled library's capability in opening a "
+         "FITS file, and also spinning-off threads.\n");
+
+
+  /* A small sanity check: this is only intended for 2D arrays. */
+  if(p.image->ndim!=2)
     {
-      fprintf(stderr, "%zu bytes could not be allocated for prm.",
-              numthreads*sizeof *prm);
+      fprintf(stderr, "only 2D images are supported.");
       exit(EXIT_FAILURE);
     }
 
-  /* Distribute the actions into the threads: */
-  gal_threads_dist_in_threads(numactions, numthreads, &indexs, &thrdcols);
 
-  /* Do the job: when only one thread is necessary, there is no need to
-     spin off one thread, just call the function directly (spinning off
-     threads is expensive). This is for the generic thread spinner
-     function, not this simple function where `numthreads' is a
-     constant. */
-  if(numthreads==1)
-    {
-      prm[0].id=0;
-      prm[0].b=NULL;
-      prm[0].indexs=indexs;
-      worker(&prm[0]);
-    }
-  else
-    {
-      /* Initialize the attributes. Note that this running thread
-         (that spinns off the nt threads) is also a thread, so the
-         number the barriers should be one more than the number of
-         threads spinned off. */
-      numbarriers = (numactions<numthreads ? numactions : numthreads) + 1;
-      gal_threads_attr_barrier_init(&attr, &b, numbarriers);
-
-      /* Spin off the threads: */
-      for(i=0;i<numthreads;++i)
-        if(indexs[i*thrdcols]!=GAL_BLANK_SIZE_T)
-          {
-            prm[i].id=i;
-            prm[i].b=&b;
-            prm[i].indexs=&indexs[i*thrdcols];
-            err=pthread_create(&t, &attr, worker, &prm[i]);
-            if(err)
-              {
-                fprintf(stderr, "can't create thread %zu", i);
-                exit(EXIT_FAILURE);
-              }
-          }
-
-      /* Wait for all threads to finish and free the spaces. */
-      pthread_barrier_wait(&b);
-      pthread_attr_destroy(&attr);
-      pthread_barrier_destroy(&b);
-    }
+  /* Spin-off the threads and do the processing on each thread. */
+  gal_threads_spin_off(worker_on_thread, &p, p.image->size, numthreads);
 
-  /* Clean up. */
-  free(prm);
-  free(indexs);
 
-  /* Return. */
+  /* Clean up and return. */
+  gal_data_free(p.image);
   return EXIT_SUCCESS;
 }
diff --git a/tests/lib/multithread.sh b/tests/lib/multithread.sh
new file mode 100755
index 0000000..378da79
--- /dev/null
+++ b/tests/lib/multithread.sh
@@ -0,0 +1,48 @@
+# Run the program to test reading a FITS file to memory and writing it on
+# the command-line in multi-threaded mode.
+#
+# See the Tests subsection of the manual for a complete explanation
+# (in the Installing gnuastro section).
+#
+# Original author:
+#     Mohammad Akhlaghi <address@hidden>
+# Contributing author(s):
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved.  This file is offered as-is,
+# without any warranty.
+
+
+
+
+
+# Preliminaries
+# =============
+#
+# Set the variabels (The executable is in the build tree). Do the
+# basic checks to see if the executable is made or if the defaults
+# file exists (basicchecks.sh is in the source tree).
+img=psf.fits
+execname=./multithread
+
+
+
+
+
+# SKIP or FAIL?
+# =============
+#
+# If the actual executable wasn't built, then this is a hard error and must
+# be FAIL. But if the input doesn't exist, its not this test's fault. So
+# just SKIP this test.
+if [ ! -f $execname ]; then echo "$execname not built"; exit 99; fi;
+if [ ! -f $img      ]; then echo "$img not built";      exit 77; fi;
+
+
+
+
+
+# Actual test script
+# ==================
+$execname
diff --git a/tests/lib/versioncpp.sh b/tests/lib/versioncpp.sh
new file mode 100755
index 0000000..0d5654f
--- /dev/null
+++ b/tests/lib/versioncpp.sh
@@ -0,0 +1,45 @@
+# Run the program to build a report the Gnuastro version in C++.
+#
+# See the Tests subsection of the manual for a complete explanation
+# (in the Installing gnuastro section).
+#
+# Original author:
+#     Mohammad Akhlaghi <address@hidden>
+# Contributing author(s):
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved.  This file is offered as-is,
+# without any warranty.
+
+
+
+
+
+# Preliminaries
+# =============
+#
+# Set the variabels (The executable is in the build tree). Do the
+# basic checks to see if the executable is made or if the defaults
+# file exists (basicchecks.sh is in the source tree).
+execname=./versioncpp
+
+
+
+
+
+# Skip?
+# =====
+#
+# If the actual executable wasn't built, then this is a hard error and must
+# be FAIL. But if the input doesn't exist, its not this test's fault. So
+# just SKIP this test.
+if [ ! -f $execname ]; then echo "$execname not built"; exit 99; fi;
+
+
+
+
+
+# Actual test script
+# ==================
+$execname
diff --git a/tests/prepconf.sh b/tests/prepconf.sh
index d5a1b76..0c9bafb 100755
--- a/tests/prepconf.sh
+++ b/tests/prepconf.sh
@@ -22,14 +22,17 @@
 # along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
 
 
+
+
 # Make the .gnuastro directory
 # ----------------------------
 #
-# This directory will keep all the utility configuration files for
-# this run of `make check'.
-if [ ! -d .gnuastro ]; then
-    mkdir .gnuastro
-fi
+# This directory will keep the default configuration files for all the
+# programs. If it already exists, delete it. `mkdir_p' is the equivalent to
+# GNU's `mkdir -p' which might not exist on some systems. It comes from
+# Autoconf's tests and is exported to the test shell scripts from the
+# `tests/Makefile.am' file.
+$mkdir_p .gnuastro
 
 
 
@@ -41,19 +44,13 @@ fi
 # Copy the common options while adding the following optios only for make
 # check.
 #
-#   - The onlydirconf option is added so the utilities don't go looking
-#     into the user's home and system wide directories (which might contain
-#     configuration files from older versions). If the option names have
-#     changed or an option has been removed, such sitations will cause a
-#     failed test.
+#   - `lastconfig' will make sure that the program stop searching for
+#     configuration files after this one.
 #
-#   - When checking on multiple threads, the log files generated by the
-#     utilities can get mixed and cause failures, so it is better for the
-#     utility test scripts to not generate any log files. In the utility
-#     design, it is best that a fatal error is reported on the standard
-#     error (which will be recorded in the test outputs), not in a log
-#     file. However, a solution that would allow us to keep the log files
-#     would be to make the log file names depend on the input filenames.
+#   - Log files are not necessary during tests, they are mainly used for
+#     reporting extra information about successful tests. Failed messages
+#     will be printed on the command-line not in a log-file. So to keep
+#     this directory clean, we'll ask the programs to not generate any.
 cat > addedoptions.txt <<EOF
 
 
@@ -70,9 +67,8 @@ rm addedoptions.txt
 # Bring utility configuration files
 # ---------------------------------
 #
-# Each utility's configuration file is read and appended with the
-# addedoptions.txt file to create the configuration file which will be used
-# by `make check'.
+# Each utility's configuration file is copied in the `tests' directory for
+# easy readability.
 for prog in arithmetic convertt convolve cosmiccal crop fits      \
             mkcatalog mknoise mkprof noisechisel statistics       \
             table warp



reply via email to

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