Block Model Definition

A block model definition is a specification that describes the structure and attributes of a block model. It includes details such as block sizes, dimensions, origin, rotation, and variables. This definition can be used to create specific block model instances, such as dense or sparse block models. A block model definition is represented in the SDK with the BlockModelDefinition class.

Basic geometry

A block model definition is visualised in the viewer as a semi-transparent rectangular prism.

The prism represents the spatial extent of a block model defined with the geometry specified in the block model definition. Essentially, a block model definition specifies both the geometry and variables stored within a block model. In GeologyCore, block model definitions are mainly used for interactions with DomainMCF. In contrast, block models in a Maptek project database define their own geometry and variables independently, without relying on an external block model definition.

Creating a block model definition

To create a block model definition, start by defining the block sizes using the BlockModelDefinition.set_block_size() method, and then specify the block counts by assigning values to the BlockModelDefinition.block_counts property. For example, the following script creates a block model definition with ten blocks in the x-direction, ten blocks in the y-direction, and five blocks in the z-direction. Each block measures 1.5 metres in the x and y directions and 0.75 metres in the z-direction:

from mapteksdk.data import BlockModelDefinition
from mapteksdk.project import Project, OverwriteMode


def main(project: Project):
    with project.new(
        "block model definitions/basic example",
        BlockModelDefinition,
        overwrite=OverwriteMode.UNIQUE_NAME,
    ) as definition:
        definition.set_block_size((1.5, 1.25, 0.75))
        definition.block_counts = (10, 10, 5)


if __name__ == "__main__":
    with Project() as main_project:
        main(main_project)

This script creates a block model definition for a dense block model, where the definition does not include subblocks. To incorporate subblocks, provide a subblock ratio when calling BlockModelDefinition.set_block_size(), as demonstrated in the following snippet:

definition.set_block_size((1.5, 1.5, 0.75), SubblockRatio.ONE_HALF)

A subblock ratio of one half indicates that the subblocks are one half of the size of the primary blocks. Thus, the fragments above set the primary block size of the model to 1.5m x 1.5m x 0.75m and the subblock size to 0.75m x 0.75m x 0.325m, which is half the primary block size in every dimension.

Note

Origin

Setting the origin property translates the entire block model definition to have its origin at the specified point. For example, the statement

definition.origin = (-100, 160, 20)

translates the block model to have its origin at the point (-100, 160, 20) in world space.

Important

The origin of a block model differs form the origin of a block model definition. This difference in behaviour is a common source of confusion when working with block models and block model definitions. The two origins are defined as follows:

  • Block model origin: The centre of the block in the 0th row, column, and slice.

  • Block model definition origin: The far corner of the block in the 0th row, column, and slice.

This distinction is illustrated in the diagram below, where the origin of the block model definition is marked in blue and the origin of the block model is marked in red:

Rotation

The orientation property allows you to define the rotation of a block model definition. By default, the definition has no rotation and the x, y, and z directions are identical to the x, y, and z world directions. Once a definition has any rotation applied, the x, y, and z directions of the definition will no longer match the x, y and z directions of the world.

The rotation can be set by assigning a three-tuple of floats to the orientation property:

definition.orientation = (-15, 30, 75)

The fragment above sets the rotation of the model to have a dip of -15 degrees, a plunge of 30 degrees, and a bearing of 75 degrees.

Note
  • The x direction corresponds to columns, the y direction corresponds to rows, and the z direction corresponds to slices.

  • A block model definition will be rotated about the definition origin and a block model will be rotated about the model origin. As these are not the same point (as covered in Origin on this page), rotating a block model definition is subtly different to rotating a block model.

  • The BlockModelDefinition class restricts the dip plunge and bearing to be between -360 and 360 degrees. This is less restrictive than for block models and means that two block model definitions with non-equal rotations may have the same rotation.

Variables

In addition to the geometry of a block model, a block model definition can also define the variables that should be in the block model.

Creating Variables

You can add variables using the BlockModelDefinition.add_variable() method. The following script demonstrates how to create a variable called Example variable that takes string values:

from mapteksdk.data import BlockModelDefinition, SubblockRatio
from mapteksdk.project import Project, OverwriteMode


def main(project: Project):
    with project.new(
        "block model definitions/basic variable example",
        BlockModelDefinition,
        overwrite=OverwriteMode.UNIQUE_NAME,
    ) as definition:
        definition.set_block_size((1.5, 1.25, 0.75), SubblockRatio.ONE_QUARTER)
        definition.block_counts = (10, 10, 5)
        definition.origin = (-100, 160, 20)
        definition.orientation = (-15, 30, 75)
        definition.add_variable(
            "Example variable",
            BlockModelDefinition.VariableType.STRING,
        )


if __name__ == "__main__":
    with Project() as main_project:
        main(main_project)

Optionally, you can provide a default value for the variable. This ensures that when a block model is created from the definition, all blocks will have this default value for the variable. Modify the call to BlockModelDefinition.add_variable() as follows to set a default value:

    definition.add_variable(
        "Example variable",
        BlockModelDefinition.VariableType.STRING,
        default="NULL",
    )

This will create a string variable with a default value of NULL.

You can also provide a description for the variable. This is useful for adding context or additional information that might not be immediately apparent from the variable’s name and data type. To include a description, add the description parameter:

    definition.add_variable(
        "Example variable",
        BlockModelDefinition.VariableType.STRING,
        description="An example variable for the documentation",
    )

The BlockModelDefinition.VariableType enumeration specifies the types of variables that can be stored in a block model definition. These types correspond to the data types supported by block model definition (.bdf) files and include the following:

Enum value Description Python type
STRING Text values. str
DOUBLE An IEEE double precision floating point number. float
FLOAT An IEEE single precision floating point number. float
SHORT A 32-bit integer. int
INTEGER A 64-bit integer. int
BOOLEAN Logical values, either True or False. bool
BYTE An 8-bit integer. int

Many of the types map to the same Python type. The Python type is used to ensure valid defaults are set.

Reading variables

The BlockModelDefinition.variables() method can be used to read the existing variables of a block model definition. For example, the following script prints out the variables defined in every selected block model definition:

from mapteksdk.data import BlockModelDefinition
from mapteksdk.project import Project
from mapteksdk.operations import show_message, Severity


def main(project: Project):
    selection = project.get_selected().where(BlockModelDefinition)


    if len(selection) == 0:
        show_message(
            "Read Block Model Definition Variables",
            "This operation requires a block model definition to be selected.",
            Severity.ERROR,
        )


    for definition_id in selection:
        with project.read(definition_id) as definition:
            print_variables(definition)


def print_variables(definition: BlockModelDefinition):
    print(f'"{definition.id.name}" defines the following variables:')
    variables = definition.variables()
    if len(variables) == 0:
        print("No variables defined.")
    for variable in definition.variables():
        print("Name          :", variable.name)
        print("Type          :", variable.data_type.name)
        print("Default value :", variable.default)
        print("Description   :", variable.description)
        print("-" * 10)
    print("~" * 20)


if __name__ == "__main__":
    with Project() as main_project:
        main(main_project)

If the block models block model definitions/basic variable example and block model definitions/basic example (created in earlier examples) are selected in the project when this script is run, the following output should result:

"basic variable example" defines the following variables:
Name      	: Example variable
Type      	: STRING
Default value :
Description   :
----------
~~~~~~~~~~~~~~~~~~~~
"basic example" defines the following variables:
No variables defined.
~~~~~~~~~~~~~~~~~~~~

Editing Variables

The variables in a block model definition can be edited by assigning to the properties on the objects returned by the variables property. For example, the following script will edit the block model definition block model definitions/basic variable example (created in a previous example) to completely change the defined variable:

from mapteksdk.data import BlockModelDefinition
from mapteksdk.project import Project, ObjectDoesNotExistError, TypeMismatchError

TARGET_PATH = "block model definitions/basic variable example"


def main(project: Project):
    with project.edit(
        TARGET_PATH,
        BlockModelDefinition,
    ) as definition:
        # In this case, it is known there is only one variable so this can
        # simply edit the first variable.
        variable = definition.variables()[0]


        variable.name = "Example edit"
        variable.data_type = BlockModelDefinition.VariableType.DOUBLE
        variable.default = 3.1415
        variable.description = "Example of editing a variable."


if __name__ == "__main__":
    with Project() as main_project:
        try:
            main(main_project)
        except ObjectDoesNotExistError:
            print(
                f"There is no object at '{TARGET_PATH}'. "
                "You may not have run the earlier examples."
            )
        except TypeMismatchError:
            print(f"The object at {TARGET_PATH} is not a block model definition.")

Note
  • You do not need to edit all of the properties of a variable. The above example script only edits all of the properties for demonstration purposes.

  • If you edit the data type so that the default is no longer appropriate, the default value will be ignored until a new default is set.

Deleting variables

Use the BlockModelDefinition.remove_variable() method to delete a variable from a block model definition. For example, the following script deletes the variable on the definition block model definitions/basic variable example (created in a previous example):

from mapteksdk.data import BlockModelDefinition
from mapteksdk.project import Project, ObjectDoesNotExistError, TypeMismatchError

TARGET_PATH = "block model definitions/basic variable example"


def main(project: Project):
    with project.edit(
        TARGET_PATH,
        BlockModelDefinition,
    ) as definition:
        variable = definition.variables()[0]
        definition.remove_variable(variable)


if __name__ == "__main__":
    with Project() as main_project:
        try:
            main(main_project)
        except ObjectDoesNotExistError:
            print(
                f"There is no object at '{TARGET_PATH}'. "
                "You may not have run the earlier examples."
            )
        except TypeMismatchError:
            print(f"The object at '{TARGET_PATH}' is not a block model definition.")
        except IndexError:
            print(f"No variables to delete on '{TARGET_PATH}'")

Note
  • Deleting a variable from a block model definition will not delete the variable from any block models created using that block model definition.

  • Deleting a variable more than once will not raise an error.

    • The example script encounters an index error if run twice because it attempts to index into an empty sequence, not because the variable has been deleted.

Additional read-only properties

The BlockModelDefinition class defines several read-only variables that provide additional useful information about the model. These include the following:

block_size The primary block size as a tuple of three floats in the form (x_size, y_size, z_size).
subblock_size The subblock size as a tuple of three floats in the form (x_size, y_size, z_size). If the block model definition defines a dense model, then block_size will be equal to subblock_size. This may not be a subblock size that is well supported by DomainMCF.
rounded_subblock_size The subblock size is rounded to a value that is well supported by DomainMCF. This is the subblock size that is displayed in the Edit Block Model Definition panel in GeologyCore.
subblock_ratio The ratio in size between the primary blocks and subblocks. This is a triple of the form (x_ratio, y_ratio, z_ratio). If this block model is supported by DomainMCF, then x_ratio == y_ratio == z_ratio and the ratio will match one of the subblocking ratios supported by DomainMCF.
supported_subblock_ratio The closest ratio to a subblock ratio that is supported by DomainMCF. This is the ratio displayed in the Edit Block Model Definition panel in GeologyCore.
model_extent The size of the extent covered by the block model definition. This is the block size multiplied by the block count in each axis.

Creating a block model from a block model definition

Creating a dense block model

Use the create_dense_model_from_definition() method to create a dense block model from a block model definition, as demonstrated by the following script:

from mapteksdk.project import Project, OverwriteMode
from mapteksdk.data import BlockModelDefinition, create_dense_model_from_definition
from mapteksdk.operations import open_new_view

BASE_PATH = "block models/documentation"


def main(project: Project):
    block_counts = (3, 4, 5)
    block_sizes = (0.5, 1.5, 0.75)
    with project.new(
        f"{BASE_PATH}/definition",
        BlockModelDefinition,
        overwrite=OverwriteMode.UNIQUE_NAME,
    ) as definition:
        definition.set_block_size(block_sizes)
        definition.block_counts = block_counts
        definition.origin = (1.6, -0.6, 2.3)
        definition.orientation = (15, -30, 90)
        definition.add_variable(
            "example",
            BlockModelDefinition.VariableType.INTEGER,
            default=0,
            description="Example variable for documentation."
        )


    dense_id = create_dense_model_from_definition(project, definition.id)
    project.add_object(
        f"{BASE_PATH}/model", dense_id, overwrite=OverwriteMode.UNIQUE_NAME
    )


    open_new_view([definition.id, dense_id])


if __name__ == "__main__":
    with Project() as main_project:
        main(main_project)

The newly created dense block model has the same dimensions as the block model definition used to create it. This is demonstrated in the animation below using the juxtaposition view feature of the visibility manager:

Additionally, the newly created block model also has the variable defined by the block model definition as shown below:

Creating a dense block model filled with subblocks

By default, the block model created by create_dense_model_from_definition() will use the primary block size defined by the block model definition and ignore any subblocking present. However, by setting the use_primary_blocks optional parameter to False, the function will instead create a dense block model based on the subblock size. The following script creates two dense block models from the same block model definition—one with use_primary_blocks set to True and one with it set to False:

from mapteksdk.project import Project, OverwriteMode
from mapteksdk.data import BlockModelDefinition, SubblockRatio, create_dense_model_from_definition
from mapteksdk.operations import open_new_view

BASE_PATH = "block models/documentation"


def main(project: Project):
    block_counts = (3, 4, 5)
    block_sizes = (0.5, 1.5, 0.75)
    with project.new(
        None,
        BlockModelDefinition,
        overwrite=OverwriteMode.UNIQUE_NAME,
    ) as definition:
        definition.set_block_size(block_sizes, SubblockRatio.ONE_HALF)
        definition.block_counts = block_counts
        definition.origin = (1.6, -0.6, 2.3)
        definition.orientation = (15, -30, 90)
        definition.add_variable(
            "example",
            BlockModelDefinition.VariableType.INTEGER,
            default=0,
            description="Example variable for documentation."
        )

    primary_id = create_dense_model_from_definition(project, definition.id, use_primary_blocks=True)
    sub_id = create_dense_model_from_definition(project, definition.id, use_primary_blocks=False)
    project.add_object(
        f"{BASE_PATH}/dense_primary_blocks", primary_id, overwrite=OverwriteMode.UNIQUE_NAME,
    )
    project.add_object(
        f"{BASE_PATH}/dense_subblocks", sub_id, overwrite=OverwriteMode.UNIQUE_NAME,
    )

    open_new_view([primary_id, sub_id])


if __name__ == "__main__":
    with Project() as main_project:
        main(main_project)

The following animation uses juxtaposition view to show the difference between the two block models created by this script:

As the subblock ratio in the block model definition is set to SubblockRatio.ONE_HALF, when the dense block model is created with the subblock size it results in a block model with blocks half the size and twice as many rows, columns, and slices.

Creating a subblocked block model

The create_subblocked_model_from_definition() function is almost identical to the create_dense_model_from_definition() function, except that it always creates a subblocked block model. By way of example, let us modify the script from the previous section to call create_subblocked_model_from_definition() as follows:

from mapteksdk.project import Project, OverwriteMode
from mapteksdk.data import BlockModelDefinition, SubblockRatio, create_subblocked_model_from_definition
from mapteksdk.operations import open_new_view

BASE_PATH = "block models/documentation"


def main(project: Project):
    block_counts = (3, 4, 5)
    block_sizes = (0.5, 1.5, 0.75)
    with project.new(
        None,
        BlockModelDefinition,
        overwrite=OverwriteMode.UNIQUE_NAME,
    ) as definition:
        definition.set_block_size(block_sizes, SubblockRatio.ONE_HALF)
        definition.block_counts = block_counts
        definition.origin = (1.6, -0.6, 2.3)
        definition.orientation = (15, -30, 90)
        definition.add_variable(
            "example",
            BlockModelDefinition.VariableType.INTEGER,
            default=0,
            description="Example variable for documentation."
        )

    primary_id = create_subblocked_model_from_definition(
        project, definition.id, use_primary_blocks=True)
    sub_id = create_subblocked_model_from_definition(
        project, definition.id, use_primary_blocks=False)
    project.add_object(
        f"{BASE_PATH}/sub_primary_blocks", primary_id, overwrite=OverwriteMode.UNIQUE_NAME
    )
    project.add_object(
        f"{BASE_PATH}/sub_subblocks", sub_id, overwrite=OverwriteMode.UNIQUE_NAME
    )

    open_new_view([primary_id, sub_id])


if __name__ == "__main__":
    with Project() as main_project:
        main(main_project)

Running this script will create subblocked block models instead of dense block models:

Creating an appropriate block model depending on the definition

The create_model_from_definition() function will create a dense block model if the block model definition does not define subblocks, or a subblocked block model if the block model definition defines subblocks, as demonstrated by the following script:

from mapteksdk.project import Project, OverwriteMode
from mapteksdk.data import BlockModelDefinition, SubblockRatio, create_model_from_definition
from mapteksdk.operations import open_new_view

BASE_PATH = "block models/documentation"


def main(project: Project):
    block_counts = (3, 4, 5)
    block_sizes = (0.5, 1.5, 0.75)
    with project.new(
        None,
        BlockModelDefinition,
        overwrite=OverwriteMode.UNIQUE_NAME,
    ) as dense_definition:
        dense_definition.set_block_size(block_sizes)
        dense_definition.block_counts = block_counts

    with project.new(
        None,
        BlockModelDefinition,
        overwrite=OverwriteMode.UNIQUE_NAME,
    ) as sub_definition:
        sub_definition.set_block_size(block_sizes, SubblockRatio.ONE_HALF)
        sub_definition.block_counts = block_counts

    dense_model_id = create_model_from_definition(
        project, dense_definition.id)
    sub_model_id = create_model_from_definition(
        project, sub_definition.id)
    project.add_object(
        f"{BASE_PATH}/dense_model", dense_model_id, overwrite=OverwriteMode.UNIQUE_NAME
    )
    project.add_object(
        f"{BASE_PATH}/subblocked_model", sub_model_id, overwrite=OverwriteMode.UNIQUE_NAME
    )

    open_new_view([dense_model_id, sub_model_id])


if __name__ == "__main__":
    with Project() as main_project:
        main(main_project)

Similar to other functions that create block models from block model definitions, the create_model_from_definition() function supports setting the use_primary_blocks parameter to False. This parameter is effective only when the block model definition includes subblocks.