GNU Astronomy Utilities



12.3.15.1 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 Tile grid we will discuss functions that define/work-with a tile grid (where the tiles do not 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.

Function:
void
gal_tile_start_coord (gal_data_t *tile, size_t *start_coord)

Calculate the starting coordinates of a tile in its allocated block of memory and write them in the memory that start_coord points to (which must have tile->ndim elements).

Function:
void
gal_tile_start_end_coord (gal_data_t *tile, size_t *start_end, int rel_block)

Put the starting and ending (end point is not inclusive) coordinates of tile into the start_end array. It is assumed that a space of 2*tile->ndim has been already allocated (static or dynamic) for start_end before this function is called.

rel_block (or relative-to-block) is only relevant when tile has an intermediate tile between it and the allocated space (like a channel, see gal_tile_full_two_layers). If it does not (tile->block points the allocated dataset), then the value to rel_block is irrelevant.

When tile->block is itself a larger block and rel_block is set to 0, then the starting and ending positions will be based on the position within tile->block, not the allocated space.

Function:
void *
gal_tile_start_end_ind_inclusive (gal_data_t *tile, gal_data_t *work, size_t *start_end_inc)

Put the indices of the first/start and last/end pixels (inclusive) in a tile into the 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 work data structure (which does not have to be equal to 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 GAL_TILE_PARSE_OPERATE function-like macro that is described below.

Function:
gal_data_t *
gal_tile_series_from_minmax (gal_data_t *block, size_t *minmax, size_t 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 and in C order (slowest dimension first). The returned pointer is an allocated gal_data_t array that can later be freed with gal_data_array_free (see 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 List of gal_data_t) and passed onto the other functions described in this section.

The array keeping the minimum and maximum coordinates for each tile must have the following format. So in total minmax must have 2*ndim*number elements.

| min0_d0 | min0_d1 | max0_d0 | max0_d1 | ...
                ... | minN_d0 | minN_d1 | maxN_d0 | maxN_d1 |
Function:
gal_data_t *
gal_tile_block (gal_data_t *tile)

Return the dataset that contains tile’s allocated block of memory. If tile is immediately defined as part of the allocated block, then this is equivalent to tile->block. However, it is possible to have multiple layers of tiles (where tile->block is itself a tile). So this function is the most generic way to get to the actual allocated dataset.

Function:
size_t
gal_tile_block_increment (gal_data_t *block, size_t *tsize, size_t num_increment, size_t *coord)

Return the increment necessary to start at the next contiguous patch memory associated with a tile. block is the allocated block of memory and tsize is the size of the tile along every dimension. If coord is 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 num_increment is the main variable to this function. For the first time you call this function, it should be 1. In subsequent calls (while you are parsing a tile), it should be increased by one.

Function:
gal_data_t *
gal_tile_block_write_const_value (gal_data_t *tilevalues, gal_data_t *tilesll, int withblank, int initialize)

Write a constant value for each tile over the area it covers in an allocated dataset that is the size of tile’s allocated block of memory (found through gal_tile_block described above). The arguments to this function are:

tilevalues

This must be an array that has the same number of elements as the nodes in in tilesll and in the same order that ‘tilesll’ elements are parsed (from top to bottom, see Linked lists (list.h)). As a result the array’s number of dimensions is irrelevant, it will be parsed contiguously.

tilesll

The list of input tiles (see List of gal_data_t). Internally, it might be stored as an array (for example, the output of gal_tile_series_from_minmax described above), but this function does not care, it will parse the next elements to go to the next tile. This function will not pop-from or free the tilesll, it will only parse it from start to end.

withblank

If the block containing the tiles has blank elements, those blank elements will be blank in the output of this function also, hence the array will be initialized with blank values when this option is called (see below).

initialize

Initialize the allocated space with blank values before writing in the constant values. This can be useful when the tiles do not cover the full allocated block.

Function:
gal_data_t *
gal_tile_block_check_tiles (gal_data_t *tilesll)

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 (see Library data types (type.h)).

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 gal_tile_block_write_const_value (with withblank set to zero).

Function:
void *
gal_tile_block_relative_to_other (gal_data_t *tile, gal_data_t *other)

Return the pointer corresponding to the start of the region covered by tile over the other dataset. See the examples in GAL_TILE_PARSE_OPERATE for some example applications of this function.

Function:
void
gal_tile_block_blank_flag (gal_data_t *tilell, size_t numthreads)

Check if each tile in the list has blank values and update its flag to mark this check and its result (see Generic data container (gal_data_t)). The operation will be done on numthreads threads.

Function-like macro: GAL_TILE_PARSE_OPERATE (IN, OTHER, PARSE_OTHER, CHECK_BLANK, OP)

Parse IN (which can be a tile or a fully allocated block of memory) and do the OP operation on it. OP can be any combination of C expressions. If OTHER!=NULL, OTHER will be interpreted as a dataset and this macro will allow access to its element(s) and it can optionally be parsed while parsing over IN.

If OTHER is a fully allocated block of memory (not a tile), then the same region that is covered by IN within its own block will be parsed (the same starting pixel with the same number of pixels in each dimension). Hence, in this case, the blocks of OTHER and IN must have the same size. When OTHER is a tile it must have the same size as IN and parsing will start from its starting element/pixel. Also, the respective allocated blocks of OTHER and IN (if different) may have different sizes. Using OTHER (along with PARSE_OTHER), this function-like macro will thus enable you to parse and define your own operation on two fixed size regions in one or two blocks of memory. In the latter case, they may have different numeric data types, see Numeric data types).

The input arguments to this macro are explained below, the expected type of each argument are also written following the argument name:

IN (gal_data_t)

Input dataset, this can be a tile or an allocated block of memory.

OTHER (gal_data_t)

Dataset (gal_data_t) to parse along with IN. It can be NULL. In that case, o (see description of OP below) will be NULL and should not be used. If PARSE_OTHER is zero, only its first element will be used and the size of this dataset is irrelevant.

When OTHER is a block of memory, it has to have the same size as the allocated block of IN. When it s a tile, it has to have the same size as IN.

PARSE_OTHER (int)

Parse the other dataset along with the input. When this is non-zero and OTHER!=NULL, then the o pointer will be incremented to cover the OTHER tile at the same rate as i, see description of OP for i and o.

CHECK_BLANK (int)

If it is non-zero, then the input will be checked for blank values and OP will only be called when we are not on a blank element.

OP

Operator: this can be any number of C expressions. This macro is going to define a itype *i variable which will increment over each element of the input array/tile. itype will be replaced with the C type that corresponds to the type of INPUT. As an example, if INPUT’s type is GAL_DATA_UINT16 or GAL_DATA_FLOAT32, i will be defined as uint16 or float respectively.

This function-like macro will also define an otype *o which you can use to access an element of the OTHER dataset (if OTHER!=NULL). o will correspond to the type of OTHER (similar to itype and INPUT discussed above). If PARSE_OTHER is non-zero, then 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/or the other.

All variables within this function-like macro begin with tpo_ except for the three variables listed below. Therefore, as long as you do not start the names of your variables with this prefix everything will be fine. Note that i (and possibly o) will be incremented once by this function-like macro, so do not increment them within OP.

i

Pointer to the element of INPUT that is being parsed with the proper type.

o

Pointer to the element of OTHER that is being parsed with the proper type. o can only be used if OTHER!=NULL and it will be parsed/incremented if PARSE_OTHER is non-zero.

b

Blank value in the type of INPUT.

You can use a given tile (tile on a dataset that it was not initialized with but has the same size, let’s call it new) with the following steps:

void *tarray;
gal_data_t *tblock;

/* `tile->block' must be 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;

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 OTHER argument. Below is a demonstration, tile is the actual tile that you start with and new is the other block of allocated memory.

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, 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.... in a loop (over many tiles). */
GAL_TILE_PARSE_OPERATE(tile, faketile, 1, 1, {
    YOUR_PROCESSING_EXPRESSIONS;
  });

/* Clean up (outside the loop). */
faketile->array=NULL;
faketile->dsize=NULL;
gal_data_free(faketile);