Skip to main content

Sub-blocking in BMS

Introduction

Sub-blocking allows selected blocks within a block model to be subdivided into smaller sub-blocks. This allows finer resolution around areas of interest of the block model without drastically increasing the overall number of blocks within the block model. Sub-blocks are identified within parent blocks by one or more sub-block index columns, depending on the sub-blocking type. Each sub-block can be identified globally using either of the following:

  • Index values (i, j, k) and the sub-block index columns.
  • Coordinate values (x, y, z) and individual block size (dx, dy, dz).

Sub-blocking types supported

The Block Model API supports the following sub-blocking types:

  • Fully sub-blocked
  • Variable Octree
  • Flexible

The type of sub-blocking must be the same over the entire block model and is selected upon creation of the block model, specified by the model_type field within the size_options object in the payload.

The value of this field can be either of the following:

  • regular, for no sub-blocking.
  • fully-sub-blocked
  • variable-octree
  • flexible

Fully sub-blocked models

For fully sub-blocked models, each parent block can be subdivided into a specified uniform grid, or left whole. The number of blocks within the sub-block grid is specified by the n_subblocks_per_parent field within the size_options object in the creation payload.

n sub-blocks per parent

The field n_subblocks_per_parent specified during model creation has the following allowed schema when creating a fully sub-blocked model, where nx, ny, nz can be integers between 1 and 100.

{
"n_subblocks_per_parent": {
"nx": int,
"ny": int,
"nz": int
}
}

Variable octree models

For variable octree models, each parent block can be subdivided into a grid of sub-blocks, each of which can be potentially subdivided into its own grid of sub-blocks, and so on. This operation will be referred to as a split. Subsequent splits of sub-blocks can be applied a finite number of times. This limit of how many splits can be done is dependent on the block model field n_subblocks_per_parent.

n sub-blocks per parent

The field n_subblocks_per_parent specified during model creation has the following allowed schema when creating a variable octree model, where nx, ny, nz must be members of {1, 2, 4, 8, 16, 32, 64}.

{
"n_subblocks_per_parent": {
"nx": int,
"ny": int,
"nz": int
}
}

The values assigned to each of nx, ny, nz represent the finest allowed resolution available to sub-blocks as a ratio of the parent block on the respective axis. That is, if we have nx = 2, ny = 4, nz = 8 then the finest resolution of a sub-block is 12\frac{1}{2}, 14\frac{1}{4}, and 18\frac{1}{8} of a parent block in the xx, yy, and zz axes respectively.

Sub-blocking example

Say we have a variable octree block model with the following sub-blocking.

{
"n_subblocks_per_parent": {
"nx": 4,
"ny": 8,
"nz": 1
}
}

Take any parent block and apply a split, it must be split in half along the xx and yy axes, resulting in the four sub-blocks shown below in Fig. 1; omitting the zz axis as nz = 1 (blocks cannot be split over the zz axis). This initial split is referred to as the first level of sub-blocking.

After the first split, the sub-block resolution is 12\frac{1}{2} of a parent block in the xx and yy axes, meaning any of the sub-blocks shown in Fig. 1 can be split over both axes. Applying a split to the bottom right block along the xx and yy axes results in Fig. 2, referred to as the second level of sub-blocking. We now have a resolution in the xx axis of a 14\frac{1}{4} of a parent block, and as such none of the sub-blocks created on the second level or higher can be split over the xx axis, as nx = 4.

Fig. 3 shows a split over the yy axis on every sub-block created in Fig. 2, referred to as the third level of sub-blocking. The sub-blocks created have a resolution of 18\frac{1}{8} of a parent block, thus none of the sub-blocks created in the third level can be split over the yy axis.

Fig. 1 First levelFig. 2 Second levelFig. 3 Third level

Fig. 3 shows the highest resolution available for sub-blocks in this model. Note that multiple sub-blocks could have been split on the second level and subsequently on the third level.

As a general rule for variable octree models, each parent block can be subdivided over a combination of the x,y,zx, y, z axes into a grid of 2 (split over one axis), 4 (split over two axes), or 8 (split over all axes) sub-blocks. This subdivision can be reapplied to resultant sub-blocks, provided that the per-axis limits set by n_subblocks_per_parent are not exceeded. Additionally, if the max resolution of sub-blocks has not been reached for any axis, then it must be used when applying a split.

Flexible models

For flexible models, each parent block can contain one or more sub-blocks, each of which covers one or more cells within an underlying sub-block grid. The sub-block grid is a uniform grid of cells that covers the entire parent block, the number of cells within the sub-block grid is specified by the n_subblocks_per_parent field within the size_options object in the creation payload.

There are several other restrictions on sub-blocks within flexible models:

  • Sub-blocks must be a rectangular prism in shape.
  • Sub-blocks cannot overlap with any other sub-blocks.
  • Sub-blocks must be fully contained within a single parent block.
  • There cannot be any gaps between sub-blocks. When performing a geometry change update, you must provide all sub-blocks within a parent block, and thus they must cover the entire parent block.

n sub-blocks per parent

The field n_subblocks_per_parent specified during model creation has the following allowed schema when creating a flexible model.

{
"n_subblocks_per_parent": {
"nx": int,
"ny": int,
"nz": int
}
}

where nx, ny, nz can be integers between 1 and 100.

Sub-block index

Sub-block index columns are used to identify sub-blocks within parent blocks.

Fully sub-blocked models

For fully sub-blocked models there is a single integer sub-block index column: sidx. When a parent block is not subdivided, the sidxsidx value is 00, indicating the whole block.

To help understand the way sidxsidx is calculated for sub-blocks of parent blocks that are subdivided, imagine that the parent block is a regular block model with the following properties.

{
"n_parent_blocks": {
"nx": n_subblocks_per_parent["nx"],
"ny": n_subblocks_per_parent["ny"],
"nz": n_subblocks_per_parent["nz"],
}
}

where indexing within the parent block follows the same convention used in regular models. So any sub-block within the parent block can be identified via (si,sj,sk)(s_i, s_j, s_k), where sis_i , sjs_j , and sks_k are the indices of the sub-block within the sub-block grid. Rather than recording these three values as columns within the model, a unique sidxsidx is calculated for each.

For fully sub-blocked models, the sidxsidx of sub-blocks is calculated using: sidx=1+sisnysnz+sjsnz+sksidx = 1 + s_i \cdot s_{ny} \cdot s_{nz} + s_j \cdot s_{nz} + s_k

Where snys_{ny} and snzs_{nz} are the number of blocks in the sub-block grid along the y and z axes respectively.

For example, say we have a parent block that has been fully sub-blocked using the following values.

{
"n_subblocks_per_parent": {
"nx": 2,
"ny": 2,
"nz": 2
}
}

The parent block, viewed along the zz axis such that only the XY plane is visible, would look like the following:

In the figure above, the sidxsidx of each sub-block is shown in the center of the sub-blocks and (si,sj,sk)(s_i,s_j,s_k) is shown in the bottom-left. We can calculate sidxsidx of the bottom-right sub-block using the aforementioned formula to get the following:

sidx=1+sisnysnz+sjsnz+sk=1+122+02+0=5\begin{matrix} sidx &=& 1 + s_i \cdot s_{ny} \cdot s_{nz} + s_j \cdot s_{nz} + s_k \\ &=& 1 + 1 \cdot 2 \cdot 2 + 0 \cdot 2 + 0 \\ &=& 5 \end{matrix}

Variable octree models

For variable octree models, there is a single integer sub-block index column called sidx. It is calculated and validated using pre-order tree traversal, where the parent block is root of the tree (sidxsidx = 0).

Earlier in the variable octree sub-blocking example, we showed a valid sub-blocking configuration of a parent block up to the third level of sub-blocking. Using the same n_subblocks_per_parent configuration as in the example gives the variable octree shown in Fig. 4 below, in which the children of nodes 14 and 27 have been omitted due to horizontal real estate limitations.

Fig. 4 Expanded variable octree

Each of the levels shown in the tree above represent the sub-blocking levels outlined in the variable octree sub-blocking example, where the root of the tree is considered level zero. Below is an example showing a similar sub-blocking as in Fig. 1, 2, 3, where the sub-blocking is applied to the bottom-left sub-block in Fig. 1 and sub-blocks are now indexed and coloured to show their placement on the tree in Fig. 8.

Fig. 5 First levelFig. 6 Second levelFig. 7 Third level

Fig. 8: Coloured expanded variable octree

Sub-blocks are spatially positioned such that if the child nodes under each level of sub-blocking were indexed similarly to how parent blocks are using (i,j,k)(i,j,k), the smallest index would map to the bottom left sub-block, and so on, incrementing along the ii axis, followed by the jj, and finally the kk as shown below (omitting kk).

Fig. 9 First level indexedFig. 10 Second level indexed

Flexible models

Unlike the other sub-blocking types, flexible models do not have a single sub-block index column, instead they have six index columns: start_si, start_sj, start_sk, end_si, end_sj, and end_sk. The columns start_si, start_sj, and start_sk are the indices of the first cell of the sub-block within the sub-block grid, and end_si, end_sj, and end_sk are the indices of the last cell of the sub-block within the sub-block grid.

These are the properties of the index columns:

  • The start_s* and end_s* columns are inclusive, meaning that the first and last cells of the sub-block are included in the sub-block.
  • The end_s* columns must always be greater than or equal to the start_s* columns.
  • The start_s* and end_s* columns must be between 0 and n_subblocks_per_parent on their respective axis.

Updating sub-blocked models

Updating data in sub-blocked models has a different set of requirements than regular models.

When using the i, j, and k columns, you must also provide the sub-block index columns. On the other hand, when using x, y, and z columns, you must also provide the columns dx, dy, and dz.

In the initial update request, you must indicate whether the geometry of the sub-blocks will be changed. If the update will change the sub-blocking by creating or destroying sub-blocks, you must set the request field geometry_change to true, and provide all columns that are in the model. In this case, only new, update, and delete column operations are allowed as standalone operations. update_metadata is allowed, but only when the target columns are being updated as part of the update operation, and only when there are no columns being renamed. With regards to update type in this case:

  • If set to "merge", then the sub-blocks provided inside the uploaded file must fully cover the parent blocks that are referenced in the same file. This is even if all the columns values for that sub-block are all null.
  • If set to "replace", then it is not required that the sub-blocks of a parent block fully cover the parent block. Upon querying the block model, then only the provided sub-blocks will be returned. Sub-blocking within parent blocks that are not provided in the file will be reset to a single un-subdivided block.

If the update does not change the sub-blocking, geometry_change can be omitted or set to false.

Querying sub-blocked models

Querying data from sub-blocked models behaves like regular block models, see Querying block model data for details about the query workflow.

A few things specific to sub-blocked models:

  • When doing a query where the geometry_columns field is set to "coordinates", additional columns: dx, dy, and dz will be included in the output file. These columns represent the size of each sub-block in the xx, yy, and zz axes respectively.
  • When doing a query where the geometry_columns field is set to "indices", sub-block index columns will be included in the output file, in addition to the i, j, and k columns.
  • XYZ bbox is based on parent block centroid selection. Currently, if a parent block's centroid is selected by the XYZ bbox, then all sub-blocks will be included.

© Seequent, The Bentley Subsurface Company