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 , , and of a parent block in the , , and 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 and axes, resulting in the four sub-blocks shown below in Fig. 1; omitting the axis as nz = 1
(blocks cannot be split over the axis).
This initial split is referred to as the first level
of sub-blocking.
After the first split, the sub-block resolution is of a parent block in the and 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 and axes results in Fig. 2, referred to as the second level
of sub-blocking.
We now have a resolution in the axis of a of a parent block, and as such none of the sub-blocks created on the second level
or higher can be split over the axis, as nx = 4
.
Fig. 3 shows a split over the 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 of a parent block, thus none of the sub-blocks created in the third level
can be split over the axis.
Fig. 1 First level | Fig. 2 Second level | Fig. 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 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 value is , indicating the whole block.
To help understand the way 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 , where , , and 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 is calculated for each.
For fully sub-blocked models, the of sub-blocks is calculated using:
Where and 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 axis such that only the XY plane is visible, would look like the following:
In the figure above, the of each sub-block is shown in the center of the sub-blocks and is shown in the bottom-left. We can calculate of the bottom-right sub-block using the aforementioned formula to get the following:
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 ( = 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 level | Fig. 6 Second level | Fig. 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 , the smallest index would map to the bottom left sub-block, and so on, incrementing along the axis, followed by the , and finally the as shown below (omitting ).
Fig. 9 First level indexed | Fig. 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*
andend_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 thestart_s*
columns. - The
start_s*
andend_s*
columns must be between 0 andn_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
, anddz
will be included in the output file. These columns represent the size of each sub-block in the , , and 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 thei
,j
, andk
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.