RU 🇷🇺
Sometimes you need to map a Block Model field that isn't coded in the original Block Model. For example, Ore and Waste definitions can be more complex and multiple grades and types inputs are required. In this case, to define different properties use Custom Variable functionality implemented through the Script Editor.
Scripting language is C#.
Table of Contents |
---|
Inline formula vs Custom Variable
Creating Custom Variable
Custom Variables Examples
Dry Tonnes
Code Block | ||
---|---|---|
| ||
using System; using System.Collections.Generic; using System.Text; using System.Linq; using Alastri.Scripting; using Alastri.BlockModel.Engine.CustomVariables; public class DryTonnes : IDoubleCustomVariable { public double GetNumber(CustomVariablesContext context) { double density = context.N("DENSITY"); double volume = context.N("XINC")*context.N("YINC")*context.N("ZINC"); return (density > 0 ? density * volume : 0); } } |
Grade bins
Code Block | ||
---|---|---|
| ||
using System; using System.Collections.Generic; using System.Text; using System.Linq; using Alastri.Scripting; using Alastri.BlockModel.Engine.CustomVariables; public class Parcel : ITextCustomVariable { public string GetText(CustomVariablesContext context) { double fe = context.N("fe"); if(fe > 60) return "hg"; else if(fe > 58) return "mg"; else if(fe > 57.5) return "lg1"; else if(fe > 56) return "lg2"; else if(fe > 50) return "minw"; else return "w"; } } |
Multiple Grade Bins
Code Block | ||
---|---|---|
| ||
using System; using System.Collections.Generic; using System.Text; using System.Linq; using Alastri.Scripting; using Alastri.BlockModel.Engine.CustomVariables; public class Parcel : ITextCustomVariable { public string GetText(CustomVariablesContext context) { double fe = context.N("fe"); double al = context.N("al"); string geology = context.T("geology"); string fe_bin; if(fe > 60) { fe_bin = "60"; } else if(fe > 55) { fe = Math.Floor(fe); fe_bin = fe.ToString("#,##0"); } else { fe_bin = "50"; } string al_bin; if(al < 3) { al_bin = "3"; } else if(al < 6) { al = Math.Ceiling(al); al_bin = al.ToString("#,##0"); } else { al_bin = "9"; } string geoClass = "1"; if(geology.Equals("detrital", StringComparison.OrdinalIgnoreCase)) { geoClass = "2"; } return fe_bin + "_" + al_bin + "_" + geoClass; } } |
Ore Ratio
Rapid Reserver block model fields cannot report Stripping Ratio, because Stripping Ratio is not a sum or weight average type field. Instead, we can report ore ratio, which is the weight average of ore tonnes over total tonnes.
To do this we can set up a weight-averaged field called OreRatio as a child of "dryTonnes" or "wetTonnes" (whichever you want to report). This field will report a "1" for ore and a "0" for waste. The weight average of the 1s and 0s across a blast becomes the ore ratio.
Ore Ratio code
Code Block | ||
---|---|---|
| ||
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Alastri.Scripting;
using Alastri.BlockModel.Engine.CustomVariables;
public class OreRatio : IDoubleCustomVariable
{
List<string> ores = new List<string>(){ "hg", "mg", "lg" }; //all lower case
public double GetNumber(CustomVariablesContext context)
{
string matType = context.T("mattype").ToLower(); //material type field from original block model
bool isOre = ores.Any(ore => matType.StartsWith(ore));
if(isOre) return 1;
else return 0;
}
} |
Multiple Custom Variables
To create multiple custom variables, a class implementing the IDoubleCustomVariable or ITextCustomVariable interface needs to be created for each variable. These classes need to be listed under one another in the Custom Variables Script Editor, as shown in the examples below.
Multiple Custom Variables
Code Block | ||
---|---|---|
| ||
using System; using System.Collections.Generic; using System.Text; using System.Linq; using Alastri.Scripting; using Alastri.BlockModel.Engine.CustomVariables; public class Parcel : ITextCustomVariable { public string GetText(CustomVariablesContext context) { double fe = context.N("fe"); if(fe > 60) return "hg"; else if(fe > 58) return "mg"; else if(fe > 57.5) return "lg1"; else if(fe > 56) return "lg2"; else if(fe > 50) return "minw"; else return "w"; } } public class DryTonnes : IDoubleCustomVariable { public double GetNumber(CustomVariablesContext context) { double density = context.N("DENSITY"); double volume = context.N("XINC")*context.N("YINC")*context.N("ZINC"); return (density > 0 ? density * volume : 0); } } |
Multiple variables with shared logic
Code Block | ||
---|---|---|
| ||
using System; using System.Collections.Generic; using System.Text; using System.Linq; using Alastri.Scripting; using Alastri.BlockModel.Engine.CustomVariables; //block model 1 has a "parcel1" variable public class Parcel1 : ITextCustomVariable { public string GetText(CustomVariablesContext context) { string parcel = context.T("mtype"); //block model 1 field return ParcelResolver.Parcel(parcel); } } //block model 2 has a "parcel2" variable public class Parcel2 : ITextCustomVariable { public string GetText(CustomVariablesContext context) { string parcel = context.T("ioretype"); // block model 2 field return ParcelResolver.Parcel(parcel); } } //parcel logic is wrapped up in the static ParcelResolver class public static class ParcelResolver { private static List<string> _oreList = new List<string> { "hg", "hg1", "bl1", "mg", "lg", "lg1", "lg2", "mw" }; public static string Parcel(string parcel) { if(_oreList.Contains(parcel.ToLower())) return "ore"; else return "waste"; } } |
Access Custom Variable from another Custom Variable
Code Block | ||
---|---|---|
| ||
using System; using System.Collections.Generic; using System.Text; using System.Linq; using Alastri.Scripting; using Alastri.BlockModel.Engine.CustomVariables; public class Parcel : ITextCustomVariable { public string GetText(CustomVariablesContext context) { double fe = context.N("fe"); if(fe > 60) return "hg"; else if(fe > 58) return "mg"; else if(fe > 57.5) return "lg1"; else if(fe > 56) return "lg2"; else if(fe > 50) return "minw"; else return "w"; } } public class Recovery : IDoubleCustomVariable { public double GetNumber(CustomVariablesContext context) { Parcel parcel = new Parcel(); //Create an instance of the Parcel object string p = parcel.GetText(context); //Call the GetText() method, store the result in variable 'p' double volume = context.N("XINC")*context.N("YINC")*context.N("ZINC"); if(p == "hglp" ) return volume * 1.20; else if(p == "hg") return volume * 1.20; else if(p == "mg") return volume * 1.20; else if(p == "lg1") return volume * 1.20; else if(p == "lg2") return volume * 0.85; else return 0; } } |
Access Custom Variable values from another Custom Variable
Code Block | ||
---|---|---|
| ||
// Reading Factors from one variable into a second variable // Update the ROM Recon Factors below public class reconFactorVariable_1 { double fe_F = 1.0; double al_F = 1.0; public double GetReconValue(CustomVariablesContext context, string code) { if (code.Equals("fe_F",StringComparison.OrdinalIgnoreCase)) return fe_F; if (code.Equals("al_F",StringComparison.OrdinalIgnoreCase)) return al_F; return 1; } } public class fe_R_Variable_2 : IDoubleCustomVariable { public double GetNumber(CustomVariablesContext context) { var rf = new reconFactorVariable_1(); double grade = context.N("i_fe"); grade = grade * rf.GetReconValue(context,"fe_F"); return grade; } } public class al_R_Variable_2 : IDoubleCustomVariable { public double GetNumber(CustomVariablesContext context) { var rf = new reconFactorVariable_1(); double grade = context.N("i_al"); grade = grade * rf.GetReconValue(context,"al_F"); return grade; } } |
Variable validation and Error list resolution
Check if the statement is correct by pressing the Compile button at the top left corner of the Script Editor.
If you made a mistake, the Compile Error window will pop up, showing row and column of an error with a short description of its type.
In the example on the rightб Сompile Error dialog is pointing that semicolon is missing
Read the error message description and correct the lines specified.