Developing Efficient RPL Expressions
RPL expressions are built using the Palette; see
RPL Palette for details. Together with user and predefined functions, these provide all of the pieces necessary to create a simple or complex RPL expression; see
RPL Predefined Functions Reference for details. Typically, an analysis of your RPL set performance is necessary to locate slow or inefficient items. See
RPL Analysis Tool in Debugging and Analysis for details on the tools, particularly the RPL Analysis Tool.
Following are some suggestions to writing efficient RPL sets in terms of performance.
• Use predefined functions or operators when available. In general, always prefer a built-in operator or predefined function to a user-defined function (or complex expression) which performs the same computation.
• Move complex logic to user defined functions. This not only makes the logic more readable and easier to debug, but it makes performance analysis easier. This is because the RPL set analysis tool reports the times for function calls but not for other parts of expressions (i.e., the granularity of the performance information is per function).
• Use WITH expressions to avoid re-evaluating expensive expressions.
• Make sure there is no unnecessary LIST processing or STRING manipulation.
• OBJECT and SLOT representations of workspace objects and slots are generally more efficient than string representations of them. For example, the expression
GetSlot( (STRINGIFY reservoir) CONCAT “^” CONCAT account CONCAT “.Storage” )
takes significantly longer to evaluate (and is more complex) than
reservoir ^ ( account CONCAT “.Storage” )
This also is slower and harder to read than
reservoir ^ account . “Storage”
When accessing accounting slots, the final option is preferred for performance and readability.
• For a large model, it is computationally expensive to obtain a SLOT given the full slot name (i.e., a STRING representation of the slot) because RiverWare must first break the string into its components, then look for an object with the appropriate name. Once the object is found, then for accounting slots RiverWare must search through the accounts. Finally a search is conducted for a slot on the object/account with the given slot name. Thus when referencing slots, one should take special care to apply the suggestions mentioned above.
• Make sure that time consuming functions like FloodControl() or the hypothetical simulation functions are not being called more than necessary.
• Use functions with no arguments to cache values. If a function has no arguments, then the first time it is executed in a block (a rule, accounting method, optimization goal, initialization rule, MRM rule or expression slot), the return value is cached. For the remainder of the block execution, the function need not be evaluated again, the cached value is used. Thus, if you have multiple assignments within one rule that call the same argument-less function, the function will be evaluated once and the value will be used for all function calls.
• If you are sure that a function with no arguments is always going to return the same value regardless of the timestep, set the
Set Time Varying toggle to be off. This will lead to the function’s first return value being reused throughout the run. See
Time-invariant Functions and Function Value Caching for details.
• MAPLIST is an efficient expression which operates on a list and returns a list, but if one wants to operate on a list and compute a single value, FOR expressions (or a variation of FOR, like SUM or AVE) are more efficient. E.g.
Sum( MAPLIST (...))
is slower than
FOR ( ... ) SUM
...
END FOR