OpenZGY/C++ API and Internals (ALPHA)
Access seismic data stored in ZGY format.
Namespaces | Functions
subtiling.cpp File Reference

Handle 8x8 subtiling. More...

#include "subtiling.h"
#include <cstdint>
#include <array>
#include <string.h>

Namespaces

 InternalZGY
 Implementation not visible to clients.
 

Functions

void InternalZGY::subtiling (const std::array< std::int64_t, 3 > &bricksize, std::int64_t itemsize, void *dst, const void *src, bool remove)
 

Detailed Description

Handle 8x8 subtiling.

Version 1 of the uncompressed ZGY format reorganized the contents of alpha tiles and data bricks before writing. Instead of keeping the 64x64(x64) layout, they were changed to consisting of 8x8 subtiles/bricks each holding 8x8(x64) samples. This was done to provide faster access to inline/crossline sections, as the reader would then not need to load full 64x64(x64) tiles/bricks, but could concentrate only on the much smaller (1/64th) 8x8(x64) subtiles/bricks that intersected the section of interest.

Starting with version 2, such subtiling is no longer done.

When reading and writing files of version 1, the 8x8 subtiling is handled by treating the data as being of higher dimension and using a general permutation function. The rationale is as follows.

Consider a brick of size N[3]. In the two first dimensions it is subtiled with tiles of size n[2]. The offset of sample i[3] is then:

  offset(i) = (i[0] DIV n[0]) * (n[0]*N[1]*N[2])
            + (i[1] DIV n[1]) * (n[0]*n[1]*N[2])
            + (i[0] MOD n[0]) * (n[1]*N[2])
            + (i[1] MOD n[1]) * (N[2])
            + (i[2])          * (1)

where the two first lines correspond to indexing a specific subtile, and the last three lines correspond to indexing within the subtile.

For the non-subtiled variant of the brick, the offset of sample i[3] is simply:

  offset(i) = i[0]*N[1]*N[2] + i[1]*N[2] + i[2]

This can be rearranged into

  offset(i) = (i[0] DIV n[0]) * (n[0]*N[1]*N[2])
            + (i[1] DIV n[1]) * (n[1]*N[2])
            + (i[0] MOD n[0]) * (N[1]*N[2])
            + (i[1] MOD n[1]) * (N[2])
            + (i[2])          * (1)

which takes the same form as the offset for the subtiled brick.

Both cases can now be viewed as finding the offset of sample x[5] in a 5- dimensional dataset of size { N[0]/n[0], N[1]/n[1], n[0], n[1], N[2] } with stride S[5]:

  offset(x) = x[0]*S[0] + x[1]*S[1] + x[2]*S[2] + x[3]*S[3] + x[4]*S[4]

where the indices in both cases are defined by

  x = { i[0] DIV n[0], i[1] DIV n[1], i[0] MOD n[0], i[1] MOD n[1], i[2] }

and the strides are

  S = { n[0]*N[1]*N[2], n[0]*n[1]*N[2], n[1]*N[2], N[2], 1 }
  S = { n[0]*N[1]*N[2], n[1]*N[2], N[1]*N[2], N[2], 1 }

for the subtiled and non-subtiled bricks, respectively.

With only strides differing (in zero-based element 1 and 2), we can then convert between the two by applying a general 5-dimensional permutation. Since the last two strides are equal, we can in practice achieve the correct permutation by using only 4-dimensions. This corresponds to treating each vertical plane of the subtiles as a 1-dimensional array.