Pit Optimisation

Which blocks should be mined to maximise profit? Learn block economic values, slope precedence, the Lerchs–Grossmann algorithm and pseudoflow, revenue-factor nested pits, pit-by-pit graphs, and how optimised shells become practical pushbacks — with a Python dynamic-programming pit optimiser.

A block model may contain millions of blocks, each ore or waste. Removing an ore block requires removing all blocks above it within the slope cone. Pit optimisation finds the set of blocks with maximum total value that respects these slope constraints — the ultimate pit.

The Lerchs–Grossmann algorithm (1965) solves this exactly; modern software (Whittle, Deswik, MineSight) uses LG or faster pseudoflow methods.

An analogy

Pit optimisation is like deciding how deep to dig into a cake to reach cherries: each cherry costs you all the cake above it, so only cherries worth more than their 'cake cone' are worth taking.

Block economic values

Each block gets a dollar value: revenue from recovered metal minus mining and processing cost if it is ore, or minus mining cost if waste. The optimiser only needs these values and slope precedence rules.

Nested pits and pit-by-pit analysis

Running the optimiser at a range of revenue factors (e.g. 30–130 % of base price) generates nested shells from the highest-value core outward. The pit-by-pit graph shows cumulative ore, waste and discounted value per shell — used to select the ultimate pit and pushbacks.

From shell to design

Optimised shells have jagged block outlines; engineers design practical pits with ramps, minimum mining widths and berms. Design usually loses a few percent of shell value.

Beyond LG

LG maximises undiscounted value; NPV depends on sequence. Direct block scheduling (MILP), stochastic optimisation under grade uncertainty, and simultaneous optimisation of pit, stockpiles and cut-off (e.g. SimSched, Whittle SIP) improve NPV.

Formulas

Worked example: Ore block value

Given: Block 10 000 t @ 0.8 % Cu, recovery 88 %; Net price $8.5/kg; Mining $2.5/t, processing $12/t

Find: BEV.

Answer: +$453k (a waste block of same size = −$25k)

Worked example: 2D pit

Given: Block values in the code sample

Find: Optimal pit.

Answer: Optimal value $24k — the deepest ore block is left

2D Lerchs–Grossmann (dynamic programming)

import numpy as np

# Block economic values ($k): rows = benches (0 = top), cols = x
V = np.array([
    [-4, -4, -4, -4, -4, -4, -4],
    [-4, -4,  6, 10,  6, -4, -4],
    [-4, -4, -4, 22, -4, -4, -4],
    [-4, -4, -4, 12, -4, -4, -4],
], dtype=float)

def optimal_pit_2d(V):
    """Lerchs-Grossmann 2D dynamic programme, 45-degree slopes."""
    nz, nx = V.shape
    # add an 'air' row on top (value 0) and cumulative column values
    M = np.vstack([np.zeros(nx), np.cumsum(V, axis=0)])
    P = np.full((nz + 1, nx + 1), -np.inf)
    P[0, 0] = 0.0                              # start outside the pit, at surface
    for x in range(1, nx + 1):
        for z in range(nz + 1):
            best_prev = max(P[zz, x - 1] for zz in (z - 1, z, z + 1) if 0 <= zz <= nz)
            P[z, x] = M[z, x - 1] + best_prev
    return max(P[0, nx], P[1, nx]), P          # pit exits at the surface edge

value, P = optimal_pit_2d(V)
print(f"Optimal pit value: ${value:.0f}k")     # -> $24k (mine down to bench 3)

Each column's pit bottom can change by at most one bench from its neighbour (45° slopes with square blocks). M holds the cumulative value of mining a column to depth z; P accumulates the best pit ending at each column. The deepest block (value 12) is left because its cone of waste (row 0–2 extensions) costs more than it earns.

Common mistakes

Applications

Key takeaways

Going further