< All Topics

3D stochastic beach slope modelling

In the previous tutorial, a stochastic slope model based on the approach presented by Seddon et al (2015) and implemented for a simple 2D deposition model.  In this tutorial we’ll take the same model and implement it for 3D tailings deposition.

Seddon, KD, Pirouz, B & Fitton, TG 2015, ‘Stochastic beach profile modelling’, in R Jewell & AB Fourie (eds), Proceedings of the 18th International Seminar on Paste and Thickened Tailings, Australian Centre for Geomechanics, Perth, pp. 455-465.

Base topography

The base topography for this example is from the PineRiver Hills dataset and is linked at the bottom of this page.  A single discharge point is also included in the archive.

mceclip0.png

Create a new working directory and save the data files.

Recording a macro

The next step is to record a macro of a deposition run.  The deposition model that we’ll use will be Single stream/No pond/Flow path down slope. Before starting the recording, make sure that Ooze/Automatically fix deposition runs is checked (active).

Start recording a macro with Scripts/Record macro and call it pour_tailings.py.

Record the following steps:

  • Clear graphics.
  • Single stream/No pond/Flow path down slope.
mceclip1.png

The macro is shown below.  Make sure that in Line 4 the dont_ask keyword argument for Clear graphics is set to True.

# running command Clear graphics
# Parameters from dialog
cmd = get_command('Clear graphics')
result = cmd({   'dont_ask': True})

# running command Single stream no pond, auto flow path
# Parameters from dialog
cmd = get_command('Single stream no pond, auto flow path')
result = cmd({   'base': u'grid-10.mgrid',
    'deposition model': 'Single stream no pond, auto flow path',
    'dischargePoints': u'discharge_1.mcurve',
    'discharge_line_offset': 0.0,
    'initialDischargeElevation': 130.0,
    'maxChange': 2.0,
    'maxIterations': 40,
    'maxPondIterations': 1,
    'pond_location': None,
    'tailings': u'test',
    'tolerance': 1.0,
    'tonnage': 10000.0,
    'verticalOffset': 0.0})

Don’t worry about the tailings stream at the moment.  One has to be defined to run the deposition model, but we’ll be substituting our own tailings definition with the slope from the stochastic model.

Setting up the stochastic slope model

For this, we’ll copy part of the script from the previous tutorial.  Lines 1 to 24 were copied from the script in the last tutorial.

import numpy
import scipy.stats as stats
import scipy.interpolate as interpolate


solids_concentration = stats.norm(loc=62.8, scale=3.14)
mass_flow_rate = stats.norm(loc=1250, scale=150)


Beach_Slopes = """	0.39	0.38	0.36	0.35	0.33	0.3	0.27
56.65	0.58	0.6	0.61	0.62	0.64	0.67	0.71
59.19	0.73	0.75	0.77	0.78	0.81	0.84	0.9
61.15	0.87	0.89	0.91	0.93	0.96	1.01	1.07
62.8	1.02	1.05	1.07	1.09	1.13	1.18	1.25
64.45	1.2	1.24	1.26	1.29	1.33	1.39	1.48
66.41	1.49	1.54	1.57	1.6	1.66	1.73	1.84
68.95	2.03	2.08	2.13	2.17	2.25	2.36	2.51"""

slope_rows = Beach_Slopes.split('\n')
slope_x_indices = map(float, slope_rows[0].split('\t')[1:])
slope_y_indices = map(float, [r.split('\t')[0] for r in slope_rows[1:]])
slope_data = [map(float, r.split('\t')[1:]) for r in slope_rows[1:]]

slope_interpolator = interpolate.interp2d(slope_x_indices, slope_y_indices, slope_data)

# running command Clear graphics
# Parameters from dialog
cmd = get_command('Clear graphics')
result = cmd({   'dont_ask': True})

# running command Single stream no pond, auto flow path
# Parameters from dialog
cmd = get_command('Single stream no pond, auto flow path')
result = cmd({   'base': u'grid-10.mgrid',
    'deposition model': 'Single stream no pond, auto flow path',
    'dischargePoints': u'discharge_1.mcurve',
    'discharge_line_offset': 0.0,
    'initialDischargeElevation': 130.0,
    'maxChange': 2.0,
    'maxIterations': 40,
    'maxPondIterations': 1,
    'pond_location': None,
    'tailings': u'test',
    'tolerance': 1.0,
    'tonnage': 10000.0,
    'verticalOffset': 0.0})

Using a custom tailings

In the recorded macro, tailings properties are specified by referencing the name of a user defined tailings.  Since we want to manually specify the beach slope, we need to use a function in the Muk3D API to create tailings properties in code called muk3d.ooze.create_linear_tailings.

Line 4: From the module muk3d.ooze we import the function create_linear_tailings.

Line 26-27: A function was added to get the slope by interpolating the slope from mass_flow_rate and solids_concentration.  It’s also converted to a float – the interpolation command returns a 1×1 array – and divided by 100.0 to get the slope as a decimal fraction.

Line 46: The tailings entry is commented out.

Line 47: The key ‘user tailings‘ is set to contain the results of create_linear_tailings, with a beach slope drawn from the lookup table, and a beach below water of 1 (its not used in this instance, so the value isn’t important).

Run the script.

import numpy
import scipy.stats as stats
import scipy.interpolate as interpolate
from muk3d.ooze import create_linear_tailings

solids_concentration = stats.norm(loc=62.8, scale=3.14)
mass_flow_rate = stats.norm(loc=1250, scale=150)


Beach_Slopes = """	0.39	0.38	0.36	0.35	0.33	0.3	0.27
56.65	0.58	0.6	0.61	0.62	0.64	0.67	0.71
59.19	0.73	0.75	0.77	0.78	0.81	0.84	0.9
61.15	0.87	0.89	0.91	0.93	0.96	1.01	1.07
62.8	1.02	1.05	1.07	1.09	1.13	1.18	1.25
64.45	1.2	1.24	1.26	1.29	1.33	1.39	1.48
66.41	1.49	1.54	1.57	1.6	1.66	1.73	1.84
68.95	2.03	2.08	2.13	2.17	2.25	2.36	2.51"""

slope_rows = Beach_Slopes.split('\n')
slope_x_indices = map(float, slope_rows[0].split('\t')[1:])
slope_y_indices = map(float, [r.split('\t')[0] for r in slope_rows[1:]])
slope_data = [map(float, r.split('\t')[1:]) for r in slope_rows[1:]]

slope_interpolator = interpolate.interp2d(slope_x_indices, slope_y_indices, slope_data)

def get_slope():
    return float( slope_interpolator(mass_flow_rate.rvs(), solids_concentration.rvs()))/100.0
# running command Clear graphics
# Parameters from dialog
cmd = get_command('Clear graphics')
result = cmd({   'dont_ask': True})


# running command Single stream no pond, auto flow path
# Parameters from dialog
cmd = get_command('Single stream no pond, auto flow path')
result = cmd({   'base': u'grid-10.mgrid',
    'deposition model': 'Single stream no pond, auto flow path',
    'dischargePoints': u'discharge_1.mcurve',
    'discharge_line_offset': 0.0,
    'initialDischargeElevation': 130.0,
    'maxChange': 2.0,
    'maxIterations': 40,
    'maxPondIterations': 1,
    'pond_location': None,
    # 'tailings': u'test',
    'user tailings': create_linear_tailings(get_slope(), 1),
    'tolerance': 1.0,
    'tonnage': 10000.0,
    'verticalOffset': 0.0})

Doing multiple deposition runs

Once we’ve got it running for a single deposition run, we can wrap it in a loop and use a different tailings slope each time. 

Line 29: A variable called base_grid is created to store the name of the current base grid.  For the first run, it will be grid-10.mgrid, but for subsequent runs it will be the previous deposition runs output_grid.mgrid.

Line 31: A for loop will run 10 times.

Line 41: The base grid for the deposition run is set to be the base_grid variable.

Line 56: The value of the base_grid is set to be output_grid,mgrid.

import numpy
import scipy.stats as stats
import scipy.interpolate as interpolate
from muk3d.ooze import create_linear_tailings

solids_concentration = stats.norm(loc=62.8, scale=3.14)
mass_flow_rate = stats.norm(loc=1250, scale=150)


Beach_Slopes = """	0.39	0.38	0.36	0.35	0.33	0.3	0.27
56.65	0.58	0.6	0.61	0.62	0.64	0.67	0.71
59.19	0.73	0.75	0.77	0.78	0.81	0.84	0.9
61.15	0.87	0.89	0.91	0.93	0.96	1.01	1.07
62.8	1.02	1.05	1.07	1.09	1.13	1.18	1.25
64.45	1.2	1.24	1.26	1.29	1.33	1.39	1.48
66.41	1.49	1.54	1.57	1.6	1.66	1.73	1.84
68.95	2.03	2.08	2.13	2.17	2.25	2.36	2.51"""

slope_rows = Beach_Slopes.split('\n')
slope_x_indices = map(float, slope_rows[0].split('\t')[1:])
slope_y_indices = map(float, [r.split('\t')[0] for r in slope_rows[1:]])
slope_data = [map(float, r.split('\t')[1:]) for r in slope_rows[1:]]

slope_interpolator = interpolate.interp2d(slope_x_indices, slope_y_indices, slope_data)

def get_slope():
    return float( slope_interpolator(mass_flow_rate.rvs(), solids_concentration.rvs()))/100.0

base_grid = 'grid-10.mgrid'

for i in range(10):    
    # running command Clear graphics
    # Parameters from dialog
    cmd = get_command('Clear graphics')
    result = cmd({   'dont_ask': True})


    # running command Single stream no pond, auto flow path
    # Parameters from dialog
    cmd = get_command('Single stream no pond, auto flow path')
    result = cmd({   'base': base_grid,
        'deposition model': 'Single stream no pond, auto flow path',
        'dischargePoints': u'discharge_1.mcurve',
        'discharge_line_offset': 0.0,
        'initialDischargeElevation': 130.0,
        'maxChange': 2.0,
        'maxIterations': 40,
        'maxPondIterations': 1,
        'pond_location': None,
        # 'tailings': u'test',
        'user tailings': create_linear_tailings(get_slope(), 1),
        'tolerance': 1.0,
        'tonnage': 10000.0,
        'verticalOffset': 0.0})
    
    base_grid = 'output_grid.mgrid'

Some enhancements

The make the script run a little more efficiently, there’s a few changes to make.  The first is to do a better job of the initial discharge elevation.  We can use the results of the deposition run to (perhaps) refine the initial elevation guess.  Not every deposition run will lead to an increase in the maximum elevation of the tailings stack. At the end of each deposition run, the deposition elevation will be retrieved and if higher than the current elevation guess, the current elevation guess will be changed.

The other feature will be to implement a stop button in case we want to halt the script.

Line 4: We import the get_deposition_result from the muk3d.ooze module.

Line 5: Import the show_stop_button function from muk3d.util.  

Line 31: Create a variable to store the current elevation guess.

Line 32: Create a variable that actually holds a function from the show_stop_button function.  When this is done a stop button will appear at the bottom right of the screen when the macro runs. We can check to see if this has been pressed by calling this variable – i.e. if stop() == True

Line 40: Test to see if the stop button has been pressed.  If True, the end() function is called to terminate the script.

Line 61: get_deposition_result is used to turn the result from the deposition run into something we can interrogate.

Line 62: Get the discharge elevation using the .get_property method with the argument ‘discharge elevation

Line 64-65: If the discharge elevation is higher than the current guess then update the current guess to this discharge elevation.

import numpy
import scipy.stats as stats
import scipy.interpolate as interpolate
from muk3d.ooze import create_linear_tailings, get_deposition_result
from muk3d.util import show_stop_button

solids_concentration = stats.norm(loc=62.8, scale=3.14)
mass_flow_rate = stats.norm(loc=1250, scale=150)


Beach_Slopes = """	0.39	0.38	0.36	0.35	0.33	0.3	0.27
56.65	0.58	0.6	0.61	0.62	0.64	0.67	0.71
59.19	0.73	0.75	0.77	0.78	0.81	0.84	0.9
61.15	0.87	0.89	0.91	0.93	0.96	1.01	1.07
62.8	1.02	1.05	1.07	1.09	1.13	1.18	1.25
64.45	1.2	1.24	1.26	1.29	1.33	1.39	1.48
66.41	1.49	1.54	1.57	1.6	1.66	1.73	1.84
68.95	2.03	2.08	2.13	2.17	2.25	2.36	2.51"""

slope_rows = Beach_Slopes.split('\n')
slope_x_indices = map(float, slope_rows[0].split('\t')[1:])
slope_y_indices = map(float, [r.split('\t')[0] for r in slope_rows[1:]])
slope_data = [map(float, r.split('\t')[1:]) for r in slope_rows[1:]]

slope_interpolator = interpolate.interp2d(slope_x_indices, slope_y_indices, slope_data)

def get_slope():
    return float( slope_interpolator(mass_flow_rate.rvs(), solids_concentration.rvs()))/100.0

base_grid = 'grid-10.mgrid'
current_discharge_guess = 112
stop = show_stop_button()

for i in range(10):    
    # running command Clear graphics
    # Parameters from dialog
    cmd = get_command('Clear graphics')
    result = cmd({   'dont_ask': True})

    if stop():
        end()
        
    # running command Single stream no pond, auto flow path
    # Parameters from dialog
    cmd = get_command('Single stream no pond, auto flow path')
    result = cmd({   'base': base_grid,
        'deposition model': 'Single stream no pond, auto flow path',
        'dischargePoints': u'discharge_1.mcurve',
        'discharge_line_offset': 0.0,
        'initialDischargeElevation': current_discharge_guess,
        'maxChange': 2.0,
        'maxIterations': 40,
        'maxPondIterations': 1,
        'pond_location': None,
        # 'tailings': u'test',
        'user tailings': create_linear_tailings(get_slope(), 1),
        'tolerance': 1.0,
        'tonnage': 10000.0,
        'verticalOffset': 0.0})
        
    dep_result = get_deposition_result(result)
    discharge_z = dep_result.get_property('discharge elevation')
    
    if discharge_z > current_discharge_guess:
        current_discharge_guess = discharge_z
    
    base_grid = 'output_grid.mgrid'
Table of Contents