GNU Astronomy Utilities



12.3.15.2 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 Independent tiles.

As discussed in 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.

Type (C struct): gal_tile_two_layer_params

The general structure to keep all the necessary parameters for a two-layer tessellation.

struct gal_tile_two_layer_params
{
  /* 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;
};
Function:
size_t *
gal_tile_full (gal_data_t *input, size_t *regular, float remainderfrac, gal_data_t **out, size_t multiple, size_t **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 regular array. If input’s size is not an exact multiple of 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 remainderfrac).

The output is an array with the same dimensions as input which contains the number of tiles along each dimension. See Tessellation for a description of its application in Gnuastro’s programs and remainderfrac, just note that this function defines only one layer of tiles.

This is a low-level function (independent of the gal_tile_two_layer_params structure defined above). If you want a two-layer tessellation, directly call gal_tile_full_two_layers that is described below. The input arguments to this function are:

input

The main dataset (allocated block) which you want to create a tessellation over (only used for its sizes). So input may be a tile also.

regular

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 input (or input->ndim).

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 input length along a dimension is not an exact multiple of the regular tile size along that dimension. See Tessellation for a more thorough discussion.

out

Pointer to the array of data structures that will keep all the tiles (see Arrays of datasets). If *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 *out points to, see multiple for more.

multiple

When *out==NULL (and thus will be allocated by this function), allocate space for multiple times the number of tiles needed. This can be very useful when you have several more identically sized inputs, and you want all their tiles to be allocated (and thus indexed) together, even though they have different block datasets (that then link to one allocated space). See the definition of channels in Tessellation and 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.

Function:
void
gal_tile_full_sanity_check (char *filename, char *hdu, gal_data_t *input, struct gal_tile_two_layer_params *tl)

Make sure that the input parameters (in tl, short for two-layer) correspond to the input dataset. filename and hdu are only required for error messages. Also, allocate and fill the tl->channelsize array.

Function:
void
gal_tile_full_two_layers (gal_data_t *input, struct gal_tile_two_layer_params *tl)

Create the two layered tessellation in 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.

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, 1, NULL);

/* 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.*/
Function:
void
gal_tile_full_permutation (struct gal_tile_two_layer_params *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 tl->permutation. If a permutation has already been defined for the tessellation, this function will not do anything. If permutation will not be necessary (there is only one channel or one dimension), then this function will not do anything (tl->permutation must have been initialized to NULL).

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       ]
Function:
void
gal_permutation_apply_onlydim0 (gal_data_t *input, size_t *permutation)

Similar to gal_permutation_apply, but when the dataset is 2-dimensional, permute each row (dimension 1 in C) as one element. In other words, only permute along dimension 0. The permutation array should therefore only have input->dsize[0] elements.

Function:
void
gal_tile_full_values_write (gal_data_t *tilevalues, struct gal_tile_two_layer_params *tl, int withblank, char *filename, gal_fits_list_key_t *keys, int freekeys)

Write one value for each tile into a file. It is important to note that the values in tilevalues must be ordered in the same manner as the tiles, so tilevalues->array[i] is the value that should be given to tl->tiles[i]. The tl->permutation array must have been initialized before calling this function with gal_tile_full_permutation.

If withblank is non-zero, then block structure of the tiles will be checked and all blank pixels in the block will be blank in the final output file also.

Function:
gal_data_t *
gal_tile_full_values_smooth (gal_data_t *tilevalues, struct gal_tile_two_layer_params *tl, size_t width, size_t numthreads)

Smooth the given values with a flat kernel of the given width. This cannot be done manually because if 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 gal_tile_full_permutation.

Function:
size_t
gal_tile_full_id_from_coord (struct gal_tile_two_layer_params *tl, size_t *coord)

Return the ID of the tile that corresponds to the coordinates coord. Having this ID, you can use the tl->tiles array to get to the proper tile or read/write a value into an array that has one value per tile.

Function:
void
gal_tile_full_free_contents (struct gal_tile_two_layer_params *tl)

Free all the allocated arrays within tl.