Sparse Block Models
In a sparse block model, all blocks are uniform in size, similar to a dense block model. However, unlike a dense block model, a sparse model can contain ‘holes’ in its three-dimensional grid structure where no blocks are present. Block properties are not stored for these holes, resulting in more efficient data storage, especially in models with numerous gaps. The sparse block model is represented in the SDK by the SparseBlockModel class.
Note: Sparse block models are primarily used by Maptek Evolution. Support for it may be incomplete in other applications.
Sparse block model examples
The following examples demonstrate how to work with sparse block models using the SDK. These examples cover various tasks, including creating a sparse block model, adding and removing blocks, and checking for duplicates.
Creating a sparse block model
When a SparseBlockModel is created, it is initially empty and contains no blocks. Before the model can be saved, blocks must be added to the model by assigning them to the SparseBlockModel.block_indices property. The SparseBlockModel.block_indices property contains one row for each existent block in the model. Each row has the form:
[slice, row, column]
which indicates that the sparse block model contains a block in the specified slice, row and column.
This is demonstrated by the following script:
from mapteksdk.project import Project from mapteksdk.data import SparseBlockModel from mapteksdk.operations import open_new_view if __name__ == "__main__": with Project() as project: with project.new("block models/new_sparse_model", SparseBlockModel( row_count=3, slice_count=3, col_count=3, row_res=1.5, col_res=1.25, slice_res=1.75 )) as model: model.block_indices = [ [0, 0, 0], [2, 0, 0], [0, 2, 0], [0, 0, 2], [2, 2, 0], [0, 2, 2], [2, 0, 2], [2, 2, 2], [1, 1, 1] ] # Nine block indices means there are nine blocks so nine block # colours are required. model.block_colours = [ [255, 165, 0, 255], [255, 165, 0, 255], [255, 165, 0, 255], [255, 165, 0, 255], [255, 165, 0, 255], [255, 165, 0, 255], [255, 165, 0, 255], [255, 165, 0, 255], [255, 0, 0, 255] ] open_new_view([model.id])
The block model created by this script is illustrated below.
-
The constructor parameters are the same for dense, sparse and subblocked block models.
-
The block count of a sparse block model is defined by the length of the block indices array.
-
If the above script used the same constructor parameters to create a dense block model, then the block model would contain
row_count * col_count * slice_count = 3 * 3 * 3 = 27
blocks. The sparse block model instead contains nine blocks, with the remaining sixteen blocks not stored. -
Because the sparse block model above only contains nine blocks, only nine colours are required to colour every block, instead of the 27 colours that would be required to colour an equivalent dense block model.
-
Blocks added to SparseBlockModel.block_indices that are outside of the model (i.e. their slice, row, or column are greater than or equal to the slice, row or column count) are silently removed when the block model is closed.
Adding blocks to an existing sparse block model
Adding blocks to an existing SparseBlockModel can be done using numpy.row_stack(), as demonstrated by the following examples:
Note: This example assumes you have already run the script provided in Creating a sparse block model.
from mapteksdk.project import Project from mapteksdk.data import SparseBlockModel import numpy as np def append_blocks_to_sparse_model( model: SparseBlockModel, new_indices: np.ndarray): """Append blocks to a SparseBlockModel. Parameters ---------- model Open sparse block model to append blocks to. new_indices Numpy array of shape (N, 3) containing the block indices to add to the model. Raises ------ ReadOnlyError If model was opened with Project.read(). ObjectClosedError If model is closed. ValueError If new_indices is the wrong shape or does not contain floats. """ model.block_indices = np.row_stack(( model.block_indices, new_indices )) if __name__ == "__main__": with Project() as project: with project.edit("block models/new_sparse_model", SparseBlockModel ) as edit_model: new_block_indices = [[1, 1, 0], [1, 1, 2]] append_blocks_to_sparse_model(edit_model, new_block_indices)
The script adds two blocks to the sparse block model, displayed in green in the following screenshot:
-
The row_stack() method added the new blocks at the end of the SparseBlockModel.block_indices array. This ensures that the existing blocks are still coloured the same as before the new blocks were added. New blocks should always be added to the end of the array.
-
The new blocks are coloured green because that is the default colour. They could be coloured differently by assigning different colours into indices nine and ten of the block colours array after the new blocks have been added.
-
Unlike a DenseBlockModel, the order of the blocks in a SparseBlockModel is not related to the topology of the model. Adjacent blocks are often not stored adjacent to each other.
-
Running the above script multiple times will add duplicate blocks to the model—two blocks that have the same block indices. Caution should be used to avoid adding duplicate blocks when adding new blocks into the model.
Removing blocks from an existing sparse block model
Blocks can be removed from a SparseBlockModel using the SparseBlockModel.remove_block() method, as demonstrated by the following script:
Note: This example assumes you have already run both the example scripts presented in Creating a sparse block model and Adding blocks to an existing sparse block model.
from mapteksdk.project import Project from mapteksdk.data import SparseBlockModel if __name__ == "__main__": with Project() as project: with project.edit("block models/new_sparse_model", SparseBlockModel ) as edit_model: edit_model.remove_block(3)
This results in the following block model:
-
The SparseBlockModel.remove_block() method should be preferred over removing from SparseBlockModel.block_indices directly because it ensures that all of the properties associated with the deleted block (e.g. the block colours) are deleted as well.
-
Multiple blocks can be deleted by calling SparseBlockModel.remove_block() multiple times.
-
Any unsaved changes to the block model are discarded when SparseBlockModel.remove_block() is called. To keep them, call SparseBlockModel.save() before SparseBlockModel.remove_block().
Checking for duplicate blocks in a sparse block model
Sparse block models can sometimes contain duplicate blocks—blocks that occupy the same position (row, column, and slice) and completely overlap each other. These duplicates can cause issues that are difficult to diagnose in algorithms. For performance reasons, the Python SDK does not automatically check for duplicate blocks. The following script enables you to identify any duplicate blocks in a SparseBlockModel.
from mapteksdk.project import Project from mapteksdk.data import SparseBlockModel from mapteksdk.operations import object_pick, write_report import numpy as np def check_for_duplicate_blocks(sparse_model: SparseBlockModel) -> bool: """Check if a SparseBlockModel contains duplicate blocks. Parameters ---------- sparse_model The open sparse block model to check for duplicate blocks. Returns ------- bool True if the sparse block model contains duplicate blocks. False if it does not. """ # If the number of unique block indices is equal to the block count, # then there are no duplicate blocks. return np.unique( sparse_model.block_indices, axis=0).shape[0] != model.block_count if __name__ == "__main__": with Project() as project: block_model_id = object_pick( object_types=SparseBlockModel, label="Pick a sparse block model to check for duplicate blocks." ) title = f"{block_model_id.path} Duplicate Blocks" with project.edit(block_model_id, SparseBlockModel) as model: has_duplicate_blocks = check_for_duplicate_blocks(model) write_report( title, str(has_duplicate_blocks) )
-
Checking for duplicate blocks in very large block models can take a prohibitively long time.
-
The script above could be modified to use SubblockedBlockModel.remove_block() to remove the duplicate blocks from the model.