Source Scheduling #6: Dependencies

Click to Print


In the previous section, we looked at how to build a Source Path. An advanced extension of Source Paths is the use of Dependencies, which is a logical application of “Don’t do this until you’ve done this”. A Dependency pairs Predecessors (do this before) and Successors (do this after).

Please note that there are six types of Dependencies in Spry:

  • Process Order: Sets Dependencies between different Tasks inside the same Leaf for example Blast waits on Drill or Coal waits on Waste.
  • Sequence: Sets Dependencies between different Tasks within a group. Normally used to create top down or bottom up vertical Dependencies.
  • Offset: Sets regular dependencies between Tasks based on one or more Offsets. Commonly used for staggers where there are roughly regular sized Solids/Mining areas.
  • Range: Sets Dependencies between ranges of Tasks by explicitly defining Predecessor and Successor pairs. Commonly used when wanting to group blocks together form a single shot together, limit mining in an area until access is established, ensure cast and dozer material isn’t blasted until the coal in the previous strip is mined or in situations where anomalies need to be controlled.
  • Cone: Sets Dependencies based on Centroids in a Cone either above or below the Task in question. Commonly used for angle of repose/highwall angle enforcement.
  • Solid Overlap: Sets dependencies where Solids overlap in Plan View based on an Overlap Percentage. This is commonly used where Destination and Source Solids intersect to ensure dumping doesn’t begin until the space is available or when blast polygons have different layouts between different benches.

As you can see each Dependency type has a “common” use but they can be flexible depending on your requirements and understanding of how they work. Some additional concepts required for fully understanding Dependencies are detailed below:

Released vs Unreleased

The key terminology to be aware of in Spry is Released (no Dependency on this Task) and Unreleased (Waiting on Dependency). This will become useful in an upcoming section where we look at the Snapshot Viewer and how it can help diagnose issues with Source Paths and Dependencies.


Pairing (Range Dependencies)

The most important concept before creating your first Range Dependency is to know how Wildcards and Spans are applied. Let’s start with something simple, say you wanted to make sure that in Strip 1, Blocks 1-10, Seam G didn’t start until Seams A-F were fully completed. You might write your dependency like this:

Predecessor: MyPit/S1/B1-B10/A-F
Successor: MyPit/S1/B1-B10/G

When you write a Span in a dependency (or a Wildcard) what you are doing is grouping the entire set of Predecessor Nodes (MyPit/S1/B1-B10/A-F) and then pairing that group with the Successor Nodes (MyPit/S1/B1-B10/G).

Key Concept: No Leaf inside the Successor pair can be worked until every Leaf inside in the Predecessor pair is 100% worked.

So in the example above, MyPit/S1/B6/G won’t get worked until every Leaf in MyPit/S1/B1-B10/A-F had been worked. Instead of a single seam (G wait on A-F) Dependency let’s say you want to make each seam (A,B,C etc) dependant on the seam before it being complete. You might be tempted to write your Dependency like this.

Predecessor: MyPit/S1/B1-B10/A-F
Successor: MyPit/S1/B1-B10/B-G INCORRECT

Just like in the example before it, everything in the Predecessor group must be finished before the Successor can be worked. In this example however there is an overlap between the groups which means that MyPit/S1/B1-B10/C is waiting on MyPit/S1/B1-B10/B (intended) but the opposite is also true (MyPit/S1/B1-B10/B is waiting on MyPit/S1/B1-B10/C) which will bring everything to a grinding halt.

What you actually want to do is explicitly pair each seam (A with B, B with C etc) and the way you do that is with Arrays.

Arrays (Range Dependencies)

However, in many/most examples you’re going to want that explicit Node to Node pairing, so in order to pair only Predecessor Seam A with Successor Seam B etc. You could get this behaviour by writing individual dependencies per line like in the following example:

Predecessor: MyPit/S1/B1-B10/A Successor: MyPit/S1/B1-B10/B
Predecessor: MyPit/S1/B1-B10/B Successor: MyPit/S1/B1-B10/C
Predecessor: MyPit/S1/B1-B10/C Successor: MyPit/S1/B1-B10/D
Predecessor: MyPit/S1/B1-B10/D Successor: MyPit/S1/B1-B10/E etc

However you can usually address this more succinctly, for which you will need to use Arrays, which were addressed briefly in the Source Path documentation.

Predecessor: MyPit/S1/B1-B10/{A;B;C;D;E;F}
Successor: MyPit/S1/B1-B10/{B;C;D;E;F;G}

By writing your Dependency with an array, you are defining your pairs explicitly and therefore Seam A will pair with Seam B etc.

Multi-Dimensional Arrays (Range Dependencies)

In the example above, we’ve applied a Seam Dependency successfully using an array, but it groups all blocks 1-10 together.. If you want to specify this Dependency to work block by block, you need to introduce the concept of an additional dimension. It’s a pretty simple addition to a regular array, except that you number each dimension of the array. It’s a little easier to visualise than explain so look at the image below.


It doesn’t really matter what number you give each array, as long as each array pair has the same length. Predecessor Array {1:} needs to match Successor Array {1:} in length and so on.

@Position, ..ArraySpan and #Jump (Range Dependencies)

Because of the pairing above, explicitly pairing items in Arrays is an important concept and the following tools will assist in pairing your predecessor and successors.

  • @Position: Uses the Index (rather than the Name) of a Position. @0 indicates the first item (zero indexed) and @-1 indicates the last (@-2 second last etc)
  • ..ArraySpan: Use this option instead of individual semi-colin delimited objects to Span multiple Positions. E.g. */*/*/*/{D..G} is the same as */*/*/*/D;E;F;G
  • #Jump: Use this option in conjunction with an ArraySpan to Jump more than one position at a time. E.g. */*/*/*/{D..G#2} is the same as */*/*/*/D;F

Example: The earlier array

Predecessor: MyPit/S1/B1-B10/{A;B;C;D;E;F}

Can now be written as

Predecessor: MyPit/S1/B1-B10/{@0..@-1}

Sequence Dependencies

Grouping Expressions

Relevant for Sequence (essential) and Solid Overlap (for performance) Dependencies. Also used in Table Plots and Proximity Contraints.

A Grouping Expression, like the name would suggest, creates Groups out of various Leaves in your Table. Dependencies are then created INSIDE each Group between the included Tasks (but not BETWEEN Groups).

When considering what to include in a Grouping Expression you should think about what what attributes are shared and include them in your expression. Conversely you want to exclude attributes that you want to create interactions between. For example in a “Dig Top Down” Dependency you want to create a Grouping Expression that includes your horizontal attributes (and excludes your vertical attributes). The resulting Grouping Expression would be similar to

Text(SourcePit) + "//" + Text(SourceStrip) + "//" + Text(SourceBlock)

Each Group created by this expression would share a Pit, Strip and Block but allow interactions between any other Levels, Positions and Tasks.

Leaf Lists

For each group created above, a list of Leaves are created. The order in which those Leaves are sorted relates to the Source/Destination Levels interface (The Index and Level Direction of each). If there are 4 Leaves in a group (A/90,A/80,B/90 and B/80) then these can be sorted in up to eight unique ways (three are below):
Leaf List

Dependency Entry Filters

By default, a Sequence Dependency only includes one Dependency Entry with a blank filter. Continuing the example above, what this does is creates a Dependency between sequential Leaves in the List (higher = predecessor, lower = successor). Using the first column this means 3 dependencies:

1: Predecessor: A/90 <All Processes> Successor: A/80 <All Processes>
2: Predecessor: A/80 <All Processes> Successor: B/90 <All Processes>
3. Predecessor: B/90 <All Processes> Successor: B/80 <All Processes>

This may be sufficient to create the type of Dependency you require but you may find you need a finer grain of detail than this. By filtering the Leaf List you can create multiple dependency entry in each group, so the following diagram demonstrates how to create a more robust top down Dependency.


Cone Dependencies

Cone Dependencies use Centroids. Any Leaf that has a Centroid inside the Cone becomes a Predecessor to the Cone’s origin Leaf. For clarity, this means that Cone Dependencies are used to create multiple predecessors. The image below is in 2 dimensions (section view) but in reality a cone is 3D.


Offset Dependencies

Offset Dependencies look at each available Leaf and create Predecessors to that Leaf by offsetting the Index of one or more Positions. That means that if an Offset is set to 0, it means “same”, an Offset of 1 means “next position” and an Offset of * means “all positions” (often used to ensure that Seams don’t interfere with Bench type Dependencies for example).


A comma between entries is the same as saying “and”. In the example below a Strip Offset of 1,-1 means look one Strip ahead and behind.


Finally a span includes all Offsets from beginning to end. In the example below a Bench offset of -2–4 means look at each Bench from 2 above to 4 above. This may be useful where Benches are not always populated.


Solid Overlap

Solid Overlap


Create a new Dependency by right-clicking “Dependencies” and choosing Add – > New “X” Dependency


Process Order Dependencies

Any model with more than one Process should normally have a Process Order Dependency. Add multiple entries to set up the hierarchy and use Ranges if it changes in different regions.

Range Dependencies

Each Range Dependency can have multiple Entries, and you can create an entry by clicking the Add Entry button source-quantity-2

Each entry is where you add the specific Predecessor and Successor details.


Relationship: Controls the Predecessor to Successor relationship. Defaults to Source to Source. Source to Destination means a Destination Task is waiting on a Source Task to be finished.

Name: Used to identify the Dependency in the Snapshot Viewer. Useful for diagnosing issues with Dependencies.

Predecessor/Successor Range: Discussed above in the Conceptual section, this is where you enter the Dependency text.

Precessor/Successor Processes: Allows you to control which Processes are used for the Dependency.

Release Delay: Once a Predecessor Range has been completed, the Release Delay controls how long until the Successor Range is considered Released and can be worked.
Right-clicking any Dependency Entry will show a menu that includes the Show Dependency Pairs option.


Note that each pair follows the key concept mentioned in the Conceptual section.


Range Dependency Act As Constraint
Normally a Dependency in Spry takes into consideration the relationship between Tasks regardless of the Equipment or Date involved. Introduced in Spry, ticking Act As Constraint on your Range Dependency adds a significant amount of power such as time conditionals (Start and End Date) as well as Equipment conditions. An example application is illustrated below, where only excavators are prevented from dumping in the strip directly opposite, leaving Equipment such as draglines, dozers and cast free to dump in that strip.

Range Dependency As Constraint

Sequence Dependencies

Besides the Grouping Expression and Dependency Entry syntax discussed in the Conceptual section, the other key practical element is the Level Direction and Index. These control how the lists of Tasks are created and in what order. The most commonly required change is the Level Direction of your Bench if your Bench doesn’t follow a logical progress of first to last in the Index (e.g if the first Indexed Bench in a Source Table is at the bottom instead of the top you would reverse the Level Direction.

Offset Dependencies

Each entry creates Predecessors based on an offset of the Position Index. For example if you wanted to ensure that you couldn’t work a Task on the Strip ahead at the same Bench it would look as simple as this

offset 2

Another example is a stagger which looks either side of a particular Task and ensures that it can go no deeper than 4 benches below Tasks on Strips on either side

offset 1

Cone Dependencies

Cone Dependencies rely on Process Centroids being set and create Dependencies based on the Direction and Angle between them. Z Limit and Radius constrain the resulting Cone for performance. A rough guide for the fastest application of this (no excess Dependencies created) is that the radius should be a little larger than your block or strip width and the Z level should be about Radius/tan(Angle). If unsure you can always make the numbers a little larger!

Solid Overlap Dependencies

Solid Overlap Dependencies compare Solids in Plan View looking up, down or both directions based on a certain Overlap Percentage. The lower the Overlap Percentage the more likely a Dependency will be created. The Expand Option will look further around the Solid and Grouping Expressions are used to improve performance by limiting the number of comparisons required.