Functions
A model element's behaviour can depend on dynamic values within the model. Functions allow you to control this behaviour via an arithmetic expression. They are used in places where you might otherwise employ a time series or a single value (eg. a node's feature editor). This page provides general information about working with functions:
Refer to the following sub-pages for more specific information:
- Types of functions and variables - Outlines the types of functions available in Source;
- Available functions, operators, variables and date ranges; and
- Functions Time of Evaluation - relates to simulation phases within a single time step.
Using functions as model inputs
The ability to use a function as a model input is a powerful way to customise model behaviour. For the purposes of discussing functions, a model element is any part of the model that can use a function as an input instead of a data source or value. This includes:
- Nodes
- Links
- Resource assessment
- Rainfall runoff models
The ability to use a function as input is indicated in Source windows in one of two ways:
- As a radio button. In this case, there is always the option of using a value or a data source as an input instead (Figure 1). When enabled, Function Editor will open below the radio button, embedded within the same window; or
- As an ellipsis button. In this case, there is always the option of using a value as an input instead (Figure 1). When selected, the Function Editor will open in a new dialog.
When a function is used directly by a model element, that element is shown under the function in the function tree, see Figure 1.
Figure 1. Using functions within a feature editor
Example use of a function
As an example, you can use a function at a Maximum Order Constraint node to limit the maximum orders for each time-step based on predicted inflow and orders. Assume that a channel constraint of 80 ML/day is required to prevent flows going overbank, except during floods (defined as more than 2,000 ML/day) when up to 3,000 ML/day is permitted as an environmental flow.
Figure 2 shows a fragment of the river network. Downstream demands are represented by a supply point and water user node. In the Function Editor, you specify the internal orders and unregulated river gain of the model using modelled variables. Maximum orders are then defined using a function.
Figure 2. Maximum Order Constraint node (example)
In this case, the following modelled variables will be assigned to these components:
$Orders assigned to the Requested Flow Rate of the Storage node; and
$predictedInflow assigned to the Inflow of the Inflow node.
Note that both variables will have a date range of Last Time Step, ML/day as designated units and Time of Evaluation as Ordering Phase.
Then, the following function will return a value of 3,000 ML/day if flows are above 2,000 ML/day but 80 ML/day otherwise.
If(($predictedinflow+$orders) > 2000, 3000, 80
Function Management
Functions can be used extensively for defining model elements in Source, as well as being used within other functions and as a stand-alone evaluation tool. This can result in a large number of functions with complex relationships being present in a model. Source has inbuilt function management capability to assist you in keeping track of your functions and variables, which should be used in conjunction with the design of a systematic approach to function organisation during the model conceptualisation process.
Function Manager
The Function Manager (Figure 3) allows you to centrally manage all functions that have been defined in Source.
The Function Manager can be accessed in one of two ways:
- Choosing View » Function Manager; or
- Clicking on the Function Manager icon in the Scenario toolbar.
It will then open in the main screen.
Figure 3. Function Manager
Function Tree Display
The Function Manager lists the functions and variables available within the active scenario in a tree menu. Items in this function tree are:
- Folders associated with built-in variables, such as End (refer to Available functions, operators, variables and date ranges);
- Folders;
- Functions;
- Variables (refer to Types of functions and variables); and
- Custom functions.
By default, when a function is used by a model element (in an inflow node for example), that element is shown in the tree under the function (function usage, Figure 3). If a function is used by multiple elements, then all usages are shown under the function in the function tree. The lock icon next to the element's name indicates that it the element is locked to using that function as an input (Crab Creek:Inflow is locked in Figure 3). See below for more information.
In addition to the function tree, the Function Manager contains a Search bar, in which you can enter text to filter the function tree, and the Function Manager toolbar.
Shown in Figure 4, the Function Manager toolbar has the following features:
- Add New... creates a new function, or variable of the type selected.
- Add New Folder creates a new folder in the function tree.
- Expand All expands all items in the function tree.
- Collapse All collapses all items in the function tree.
- Edit Functions... opens the Function Editor.
- Filters items shown in tree opens the drop-down Filter menu, which toggles the display in the function tree of function and variables by their type and/or their use. By default all functions and variables are shown, regardless of their type or their use. Note that selections are also affected by text entered into the Function Manager search bar.
Delete all unused is only active when Unused functions and variables is selected from the Filter menu. This button deletes all unused functions and variables in the function tree that also match the current filter options and text entered into the search bar. Unused items that meet the selection criteria, folders that contain only unused items, and empty folders will also be deleted. Built-in variables and custom functions will not be deleted.
Show function evaluation tree opens the Function Editor and displays the function evaluation tree for the selected function. This button is only enabled when a function is selected in the function tree.
- Show all function and variable usages displays the usages of all function and variables in the function tree.
Figure 4. Function Manager Toolbar
The contextual menus (accessed by right clicking within Function Manager, Figure 3) additionally allow you to:
- Lock All Usages in the selected folder, or in the function tree;
- Unlock All Usages in the selected folder, or in the function tree;
- Rename the selected item;
- Delete the selected item; and
- Unlock or Lock the function usage by the selected model element
Adding a function or variable
Functions and variables can be added through the Function Manager or Function Editor, the latter of which may be accessed from within other Source windows, wherever a model element indicates functions are available as an input (see above).
Follow these steps to add a variable or function using the Function Manager toolbar:
- In the function tree select the folder where you want the function to be created. If no folder is selected, the function will be added to the root folder;
- Click on Add New... (Figure X) and choose the appropriate drop-down item (This is synonymous to right-clicking the folder and choosing Add from the contextual menu);
- The Function Editor will open (if it was not open already); and
- In the Function Editor, the display on the right will depend on the type of variable or function that has been specified.
The function/variable can now be defined.
Deleting a function or variable
To delete a variable or function, choose the appropriate item in the function tree, right click, and choose Delete from the contextual menu.
Naming functions, variables and folders
- The names of functions, operators, variables and folders are not case sensitive;
- All variable and function names must begin with the "$" character, this will be added automatically.
When created, functions, variables and folders have an automatically generated name. To rename an item, either double-click on the item or right-click on it and choose Rename from the contextual menu, then type the name you wish to assign.
Functions and variables that are in different folders can have non-unique names. When called, they will be referenced using the full path to the function (incorporating the folder name). For example, consider the setup shown in Figure 5:
- $Function1 and $Function2 are in the same folder, so expressions can reference each other directly. So, the following is valid: if($Function2=5, 0, 1);
- If $Function3 references $Function2, which is in a different folder, you must use the full path to reference eg. if($Folder1.Function2=5, 0, 1); and
- Any function can reference $Function4 directly because it is not in a folder.
Figure 5. Function Editor, Naming Example
Moving Folders and Functions
Folders and Functions can be moved to new locations in the Function Editor by left clicking and dragging the Folder or Function to the new location. When moving Folders or Function the referencing of the Functions components will be automatically updated to reflect the new mapping.
Usages and references
Functions and variables can be used by other functions and model elements - this is called a usage. When a function uses another function or variable during evaluation, this is called a reference. Both usages and references can be displayed in Source, see below for more information.
Usages
By default, the direct use of a function by a model element is shown in the function tree (Figure 6). To see all other usages, select the Show all Functions and Variable usages button from the toolbar. Once toggled on (indicated by a blue box around the button), three types of usages are shown underneath applicable functions and variables in the tree:
Usage – when a function or variable is used by another function. Multiple levels of usages (eg. nested functions) can be shown. For example, Figure 6 shows that the function $count is used by the function $Percent, which in turn is used by the function $Storage_too_dry.
Recursive usage – when a function references itself. For example, $count references itself (Figure 6).
Indirect usage by a model element – when a function or variable is used indirectly as input for a model element. For example in Figure 6, the modelled variable $ModelledVar_StorVol is used by the function $TriggerFunction, which in turn is used as input for the trigger value of the 'Storage release' minimum flow requirement node.
If a function has multiple usages, it will be run once for each usage. For example, if a function has three usages it will be run once for each of the three usages. This can have implications if e.g. a function references itself because the function will reference the most recent data in the function. As an example of this: if a function uses a modelled variable on a node (which may be updated during the flow phase), usages that are before this node executes will have "yesterdays" data, but usages that execute after this node will have "today's" data. The function executes just before each node where it is used.
Figure 6. Function Usages, example
Locking and unlocking function usages
When working with a large number of functions, it is important to ensure that functions assigned to model elements are not accidentally reassigned while browsing or editing other functions. For this reason, Source has the concept of 'locking' functions to a model element, which will require you to explicitly communicate your desire to change which function is the input. If the same function is used by multiple model elements it will be locked to each element. Similar to other model elements, if a modelled time series is used by a modelled variable, it will be locked to that modelled variable, and if a data source is used by a time series variable it will be locked to that time series variable. If a function only refers to another function or variable, that function will not be locked.
Function Manager and Function Editor
All model elements that have their function usage locked are indicated in the function manager and general function editor with a closed padlock icon. Similarly, the modelled time series attached to a modelled variable will be indicated with a closed padlock icon and the data source attached to a time series variable will be indicated with a closed padlock icon. To change a locked usage, right click on the locked item and choose Unlock Usage.
Locking and unlocking usages can be managed in bulk in the function manager, or one by one in the function editor, by right clicking to access the context menu.
Function Editor accessed from within other Source windows
When you select a function as an input through another Source window (eg. a model element's feature editor) the first function you click on or add will be used and its usage locked, which is indicated by a lock icon next to the function's name in the function tree (eg. $MaxExtractionRate in Figure Y). This means that you will be able to browse the other functions and variables listed without accidentally choosing another function as the input.
To unlock a function right click and select Unlock Usage from the contextual menu. The first function you subsequently select or create will become locked.
Alternatively, while a function is still locked you can right click on another function and select Force Selection from the contextual menu, this function will become locked instead.
It is also possible to lock or unlock functions by using the contextual menus in the Function Manager window (Figure 3).
References and the Function Evaluation Tree
Selecting a function and enabling the Show function evaluation tree button will open the Function Editor and display the function evaluation tree. This displays in a tree menu structure all other functions and variables that provide values for the selected function, either directly or indirectly. For example, when the function $Storage_too_dry is evaluated, it references the function $Percent, which in turn uses several built-in variables and the functions $StorLevel and $count, and so on down the tree (Figure 7). When $Storage_too_dry is evaluated, all the other functions and variables listed are evaluated too.
Figure 7. Function Evaluation Tree, example.
Function Editor
The Function Editor (shown in Figure 8) allows you to create, define, modify and delete functions and variables. It can be accessed in several ways:
- From the main screen by choosing Edit » Functions…; or
- Choosing the edit button in the Function Manager toolbar; or
- Right-clicking on the function or variable in the Function Manager, and choosing Edit from the contextual menu; or
- From within other Source windows, see Using functions as model inputs for more information.
Figure 8. Function Editor
The Function Editor is comprised of a pane on the left side, which is similar to the Function Manager. The display to the right of the function tree is specific to the item you have selected in the tree, allowing you to define the function or variable. The display for a function is shown in Figure 8, it contains the Function Editor Toolbar along with options for configuring your function. Using the display to define a function is described below, how to define variables and custom functions is described in Types of functions and variables.
Function Editor Features
Function Editor has several features to help with writing and testing functions:
- Built-in functions – A complete list of built-in functions and operators is provided here. You can use them to to define complex functions using simple expressions. Press Ctrl+Space to view a list of available built-in functions, eg. 'min' or 'average'. These can also be viewed by using the Insert built-in function button on the toolbar (Figure 9);
- Drag and Drop – You can drag and drop variable and functions from the function tree into a function.
- Text Management – Using the Function Editor toolbar, you can load and save functions in *.txt, format, perform standard text management such as copy and paste, insert built-in functions and add or edit a note (Figure 9)
- Auto-complete – If you enter '$', you can choose which variable or function to using the list that appears. To select an item in a list, either double click it, or navigate to it with the arrow keys and press enter. Selecting items also works for the list of built-in functions (Figure 9);
- Syntax highlighting – Within the body of your expression, numerals, built-in functions and correctly formatted function and variable names will be coloured using standard Excel-style syntax to allow easy recognition (Figure 8).
- Inline comments – typing /* comment text example */ will allow you to add some descriptive text within functions that will not effect the mathematical expression (Figure 8).
- Parser – You can test your function at any time using the in-built parser. It allows you to define values for the variables and functions within your expression, and evaluates it to allow you to determine whether a) the function is valid b) returns an expected value for the variables specified. Refer to Testing Functions for more information.
To note:
- To avoid errors, variables and functions used in a function must be defined;
- White-space, including new-line markers, are ignored; and
- A blank function returns zero.
Figure 9. Function Editor, Writing Functions
Adding a note to a function
You can include a text-based message, or note, to be associated with a function. Refer to About notes for more information. Additionally, you can insert an inline comment within the body of the function's expression.
To associate a note with a function (as shown in Figure 5):
- Open the Function Editor;
- Click on the function you want to add a note to;
- In the Function Editor toolbar, click on the Add/Edit Note icon; and
- Add the text message in the window that appears.
Functions with notes are indicated by a note icon next to their name, if you hover your mouse over that icon, the note will display as a tooltip (Figure 5).
Figure 10. Function Editor, Adding a note
Writing Functions
To write or edit a function, first open the Function Editor. Either add a new function or edit an existing one, as follows:
- Type in your function. Features of the function editor help with this, see above.
- From the Result Units drop-down menu, choose which units the function will output, these need to be commensurate with where you want to use the function (eg. choose a rate if you want to use the function as an input for the Inflow node). If the result units of the function are not the same as the required units of the model input, a conversion is done of the function result before it passes the value to the model (Figure 9). Note that for the Boolean function and some conditional functions, such as the condition function in Resource Assessment Trigger, Result Units is not applicable and can use the option of no unit selected.
- Enter an Initial Value if necessary. The initial value is used until the first evaluation of the function. This means that even on the first time step, it may not be used, depending on the chosen time of evaluation. It is often useful when a function references itself.
- By default, if a function is not referenced at any model input, or by any other functions, it is not evaluated during a scenario run. Toggle on Force Evaluation to force a function to evaluate during a scenario run. This is generally used when you wish to record a function that is not used by a model element, or if a modelled variable points to a function that is not evaluated. Note that if you toggle this on for all functions, system performance is reduced.
- Under Time of Evaluation, select which simulation phase you want to evaluate the function in. It is important to choose this correctly, to ensure the correct information is used at the right time. For more information, see Functions Time of Evaluation.
Constant Functions
Note that you can set a function to a constant value. If you do so, Initial Value and Time of Evaluation will have no effect. Constant functions are evaluated before all Time of Evaluation phases.
A function is considered to be constant if it:
- has a constant expression which can be evaluated once and never change during the run (e.g. "77 + 55")
- only references other constant functions (e.g. "42 + $OtherConstantFunction")
- does not have Force Evaluate turned on.
If a function changes value from the Command Line Runner (with Modifying parameters) during a run or through a plugin such as the SubSource Plugin, then Force Evaluation needs to be turned on. Otherwise, the value of the function at the start of the run will be maintained for the entire model run.
Constant functions and Force Evaluate
- Any constant function is assigned its expression value at run initialisation, and not evaluated again.
- Any non-constant function is assigned its Initial Value at run initialisation. It is only assigned its expression value at its Time of Evaluation(s).
- When you turn on Force Evaluate on a constant function, it evaluates like a non-constant function - i.e. it will be assigned the Initial Value and not change again.
Operator precedence
Unless you use parentheses to modify the order of evaluation, operations are performed according to the precedence rules shown in Table 1. Where two operators have the same level of precedence, the operations are performed left-to-right.
Table 1. Function Editor (Evaluation order)
Order of precedence | Operator symbol | Meaning |
---|---|---|
1 (highest) | ( ) | explicit ordering |
2 | - | negation |
3 | ** and ^ | exponentiation |
4 | * and / | multiplication and division |
5 | + and - | addition and subtraction |
6 | < <= = >= > <> | comparison operators |
Referencing
A function can reference other variables, and also other functions within the same scenario, including itself. When a function references itself, the initial value is used for the first evaluation of the function.
For example: $Function1 = $Function1 + $Function2
In this case, $Function1 will use its previous evaluation value to calculate its new one.
Notice that the list shown in Figure 6 contains $Function1 as an option.
Testing Functions
Once you have defined a function, you can test its operation using the Parser (Figure 8). You can enter values for the variables and functions called by your function and confirm that the result of evaluating your function with those values is what you expect. The Parser is used as follows:
Select the function you wish to test within the Function Editor,
The Parser interface is collapsed by default, click on the arrow next to Parser (indicated in Figure 6) to display it.
The expanded Parser interface (shown in Figure 8) provides a table of all the variables and functions used in the selected function. If the variables/functions used in the function are not listed, click Update and Parse.
Enter values you wish to test (double-click on the cell, then enter a number);
Click Update and Parse again and
The test result will be displayed in the cell under the Update and Parse button.
To close the Parser interface, click on the same arrow.
If the function cannot be parsed, you will get an error icon next to the function in the Function Manager. Additionally, an error in the Log Reporter will be available at run time to indicate the same.
Figure 11. Function Editor (Parse)
Recording Functions
When functions are assigned to a model component, the function values may be used for further calculations and are not necessarily recorded explicitly. If you wish to view the function outputs over the model run, you can enable recording of a function using the Project Explorer (choose Miscellaneous » Functions). To record functions which are not used by a model element Force Evaluation will need to be turned on.
Function Logging
In addition to recording functions, function values may also be used for two types of logging to the Log Reporter during the run:
- Log Date – The result of a function can be logged in the Log Reporter for a given day, by using the Add Log Date contextual menu item for the function (Figure 8). This will output a log entry for each date specified, and will include the result of the function, as well as all the functions and variables it uses at each time of evaluation; and
- Custom Log – Based on the result of a function different log messages can be logged in the Log Reporter during the run. The custom message and notification level may be set for integral result values by using the Add Custom Logs contextual menu item for the function (Figure 8). When the function's result is one of the defined integral values a message at the specified notification level will be logged in the Log Reporter. If the level is Fatal, it will stop the run. All other function results which are not defined are ignored. Functions used for custom logs are typically written using If statements. Force Evaluation will need to be enabled if the function is not used by a model element.