Block model manipulation

Block models can be manipulated without Vulcan being opened. The following examples illustrate how to do this.

Topics:

Modules to import

Import the following libraries:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from maptek import vulcan

Open a block model

from maptek import vulcan
bm = vulcan.block_model()

bm.open('small.bmf')

Get a list of all variables

from maptek import vulcan
bm = vulcan.block_model('small.bmf')

bm.field_list()

 

Block model information

Extract some common information about the block model.

from maptek import vulcan
bm = vulcan.block_model('small.bmf')
nblocks = bm.n_blocks()
extent = bm.model_extent()
origin = bm.model_origin()
orientation = bm.model_orientation()

print("nblocks: {}".format(nblocks))
print("extents: {}".format(extent))
print("origin: {}".format(origin))
print("orientation: {}".format(orientation))

 

Get the value of a block

from maptek import vulcan
bm = vulcan.block_model('small.bmf')

grade = bm.get('au')

print("First block au value: {:.3f}".format(grade))

 

Get all values using a loop

Loop through the block model and extract all values for a particular variable.

from maptek import vulcan
def get_all_values(bm,variable):
    bm.rewind() # Go to start of block model
    data=[] # Empty list
    nblocks = bm.n_blocks() # Get number of blocks in model

    for block in bm:
        value = bm.get(variable) # Get value of block
        data.append(value) # Append to list
        bm.next() # Go to next block

    return data

bm = vulcan.block_model('small.bmf')
au_vals = get_all_values(bm, 'au')
au_vals

 

All values as a numpy array

Read all values in a variable into a numpy array. Need to have enough physical memory to read in all the data.

from maptek import vulcan
bm = vulcan.block_model('small.bmf')

au = bm.get_data('au')

 

All values in a Pandas dataframe

Read all values in a variable into a pandas dataframe. Need to have enough physical memory to read in all the data.

from maptek import vulcan
bm = vulcan.block_model('small.bmf')

data = bm.get_pandas()

data.head()

Calculate statistics on a dataframe

Calculate statistics of the Pandas dataframe using the method describe.

from maptek import vulcan
bm = vulcan.block_model('small.bmf')

data = bm.get_pandas()

data.describe()

 

Close the block model

from maptek import vulcan
bm = vulcan.block_model('small.bmf')

bm.close()

Modify a block selection

from maptek import vulcan
# open the block model
bm = vulcan.block_model('small.bmf')

# get all au and cu data inside the given solid i.e. a selection
data = bm.get_pandas(['au','cu'], '-t tq1.00t')

# change the values for the data inside the selection
data.au = 100
data.cu = 50

# write the modified data back to the block model
# the selection is maintained from the previous operation
# so the values are written into the correct locationsa
bm.put_pandas(data, ['au','cu'])

# close the block model
bm.close()

# statistics on dataframe
data.describe()

 

Sub-block model creation

An example of creating a sub-blocked model.

  1. The coordinates are in model coordinates not block.
  2. No blocks are created unless they are explicitly defined.
  3. The block model needs to be translated and rotated into the required world coordinates.
from maptek import vulcan
bm = vulcan.block_model()

xbegin = 0
ybegin = 0
zbegin = 0
xend = 50
yend = 50
zend = 50

x_num_pblock = 5
y_num_pblock = 5
z_num_pblock = 5

x_num_subblock=10
y_num_subblock=10
z_num_subblock=10

bm.create_irregular('subblock.bmf', xbegin, ybegin, zbegin, xend, yend, zend,
        x_num_pblock, y_num_pblock , z_num_pblock,
        x_num_subblock, y_num_subblock, z_num_subblock)

# Add variables to block model
bm.add_variable('au','integer','-99','gold')
bm.add_variable('cu','float','-99','copper')
bm.add_variable('lith','name','NA','lith')

# Check number of blocks, there should be none
print('Number of blocks: {0}'.format(bm.n_blocks()))

# move the origin of the block model to 100,100,50
bm.translate(100,100,50)

# actual rotation is bearing=23 but have to subtract standard vulcancan 90 degrees
# mod 360 constrains the answer to 360 degrees
bearing = (23 - 90)%360
dip = -5
plunge = -20
bm.rotate(dip, plunge, bearing)

# block length = 50/5 = 10
xlen = 10
ylen = 10
zlen = 10

# blocks are added in model space NOT world space the block is defined
# from the lower left of the 3d cube to the upper right of the 3d cube.
for i in range(0, xend, xlen):
    for j in range(0, yend, ylen):
        for k in range(0, zend, zlen):
            # calculate the min/max block
            xmin = i
            ymin = j
            zmin = k
            xmax = i+xlen
            ymax = j+ylen
            zmax = k+zlen

            # add block to block model
            bm.add_block(xmin,ymin,zmin,xmax,ymax,zmax)

# Check number of blocks after adding them all
print('Number of blocks: {0}'.format(bm.n_blocks()))
bm.close()

 

Reset a variable to default

from maptek import vulcan
'''
This script will reset a block model to the variable default using the NumPy interface.
The var_data variable is a NumPy array with the values of all the blocks in the block
model. 
The .fill function populates all values of that array with the variable default.
The data is then placed back in the model after being updated with the new values.
'''
with vulcan.block_model('small.bmf', 'w') as bm:
    var_default = bm.field_default('au')
    var_data = bm['au']
    var_data.fill(var_default)
    bm['au'] = var_data
print('Default value for au : {}'.format(var_default))

 

Block model calculation using NumPy

from maptek import vulcan
'''
The code below is an example of using NumPy to calculate the entire models
values within a single set of statements. NumPy uses large arrays of data
to make the calculations faster (~4x).
Code with # ** after it means it is syntax for the NumPy package in Python
'''
au_price = 1320
cu_price = 3.02

with vulcan.block_model('small.bmf', "w") as bm:
    # Reset the calculated variable
    au_eq = bm["au_eq"]
    au_eq.fill(0) # **

    # Get the data to work with
    au = bm["au"]
    cu = bm["cu"]

    # Set anything with values less than zero to zero (-99 or -9)
    au[au < 0] = 0 # **
    cu[cu < 0] = 0 # **

    # Calculate the new values
    au_oz = au * (1/31.1035)
    cu_lb = cu * 2240

    # Calculate the new equivalent
    au_eq = (au_oz * au_price + cu_lb * cu_price) / au_price

    # Update the values
    bm["au_eq"] = au_eq
    
    print('Average au : {:.3f}'.format(au.mean()))
    print('Average cu : {:.3f}'.format(cu.mean()))
    print('Average au_eq : {:.3f}'.format(au_eq.mean()))

 

Block model calculation

from maptek import vulcan
'''
The code below does calculation one block at a time and can be slower
but is generally simpler to use.
'''
au_price = 1320
cu_price = 3.02

with vulcan.block_model('small.bmf', "w") as bm:
    for block in bm:
        # Get the data to work with
        au = block["au"]
        cu = block["cu"]

        # Set anything with values less than zero to zero (-99 or -9)
        if au < 0:
            au = 0
        if cu < 0:
            cu = 0

        # Calculate the new values
        au_oz = au * (1/31.1035)
        cu_lb = cu * 2240

        # Calculate the new equivalent
        au_eq = (au_oz * au_price + cu_lb * cu_price) / au_price

        # Update the values
        block["au_eq"] = au_eq
    au_eq = bm["au_eq"]
    print('Average au_eq : {:.3f}'.format(au_eq.mean()))

 

Looping through a model on a single block basis

from maptek import vulcan

with vulcan.block_model('small.bmf') as bm:
    au_sum = 0.0
    for block in bm:
        if(block['au'] > 0):
            au_sum += block['au']
    ave_au = au_sum / bm.n_blocks()
    print('Average au : {:.3f}'.format(ave_au))