FindObjects
new to Analytica 5.0
FindObjects is a powerful function that searches a model to find objects that match specified criteria. For example, FindObjects('$', Units) returns a set of variables whose 'Units' attribute contains '$'. Among the vast number of criteria you can specify are the search text, the attribute(s) to search and class(s) of object to search (or exclude), what values it contains, which modules to search, variables that influence or are influenced by a variable, or whether an object has user inputs or outputs. For more complex searches, you can combine its results using set operations.
FindObjects() returns a set
The result from FindObjects is a Set -- i.e. a reference to a list of handles to the objects found. So if you want the list of objects, you should preface the function name with the de-reference operator (#), e.g.:
#FindObjects("Cost", Identifier) → [Cost_of_gasoline, Cost_of_diesel, Levelized_cost]
This example returns a list of variables whose identifiers contain "Cost".
Since FindObjects() returns a set, you can use it directly in functions like SetUnion, SetDifference and SetIntersection to combine search criteria -- for example,
#SetUnion([FindObjects('$', Units), FindObjects('₤', Units)])
returns a list of all objects whose Units contain '$' or '₤'.
The function fully supports Intelligent Arrays, meaning it works if any parameter is an array. In that case the results will be an array of sets of search result. Each cell of the array will be a reference to a list that is the result of a distinct search. You cannot dereference the result when the result might be an array of searches, so you shouldn't apply the #
operator, unless you know that it returns only a single set.
FindObjects(regExp, attribute..., excludeAttribute..., class..., excludeClass..., value, influences..., influencedBy..., inclusive, within..., withinAny..., contains..., containsAny..., hasUserInput, hasUserOutput, hasInput, hasOutput, isLiteral, outputOf..., inputOf..., caseSensitive)
FindObjects has a huge number of parameters, but all are optional. You should specify at least one parameter unless you want the set of all user-defined objects. It's simplest to use name-based calling syntax for all parameters except optionally the one or two, «regExp» and «attribute»,
Many parameters can be repeated (denoted by ... in the parameter list). For example, you can specify a list of classes and attributes. It returns the union of all objects that match. So,FindObjects('Possible', attribute: Title, Description, Class: Decision, Chance)
returns any Decision and Chance objects that have a Title or Description that contains 'Possible'.
A variable using FindObjects() does not update automatically when relevant attributes change or objects are created or deleted. (Analytica's flow architecture (automatic consistency maintenance) propagates changes only from Definitions and Values to other Variables that depend on them, not from other Attributes.) That means you must explicitly cause FindObjects() to recompute if you want to reflect any changes to the objects it may search.
regExp
This first parameters specifies text to search for. It returns a list of objects containing any attribute (or specified attribute) that contains this text value. The match is case insensitive by default. This parameter may also be a regular expression (hence its name) containing wild-cards, special characters, and more for more complex matching.
attribute
By default, FindObjects searches every user-defined attribute of each object. Or you can use this parameters to specify one or more specific attributes in which to match the «searchText» or «value». The search result doesn't include information about which attribute matched.
caseSensitive
Set to True (1) or False (0) to control whether «regExp» is case-sensitive. By default, it is case-insensitive (False).
excludeAttribute
One or more attributes to be excluded from the match.
class
Specify one or more classes of object to search, such as Variable, Objective, Function, Module, or SysFunction. It returns objects of only the specified class(es). If not specified, it searches all user-defined object classes, but not classes of built-in objects, like SysFunction and SysVar. If you specify Any, it searches all object classes, both user and built-in.
excludeClass
One of more object classes to exclude.
value
An atomic value to find. It returns any computed variable that has a matching value as its atomic value or as a cell in its array or table value (deterministic Value or Probvalue). You can search for NaN or Null. It will not find a match unless the value has been computed.
outputOf
Find objects, usually, Variables, Functions, and Buttons, that use the object(s) listed in «outputOf». Use a handle to each object, or its identifier as a text value. Don't just use the variable's identifier directly, because it will try to evaluate it -- e.g.
FindObjects(outputOf: Handle(X), 'Y')
not: FindObjects(outputOf: X, Y)
It finds Variables and Functions that mention the object(s) X in their Definitions. Unlike the simple attribute access Outputs OF X
, it also finds any Button that uses X in its Onclick attribute or any variable that uses X in its OnChange or Check attribute. It even finds Objects that use a system function or system variable. In these ways, it is more general that the Outputs attribute.
inputOf
Finds objects that are used by the objects listed in «inputOf». As with «outputOf», you should provide a handle to each variable or other object (or its identifier as text) -- and "uses" covers OnClick, OnChange, and Check attributes.
influencedBy
Finds all downstream variables, functions and buttons that are influenced by the specified object(s), directly (as in their OutputOf, above), or indirectly, via other variables or functions. As with «outputOf», you should provide a handle to each variable or other object (or its identifier as text) and "influence" includes effects via OnClick, OnChange, and Check, as well as Definition attributes.
influences
Finds all upstream variables, functions and buttons that influence the specified object(s), directly (as in their InputsOf, above), or indirectly, via other variables or functions. As with «outputOf», you should provide a handle to each variable or other object (or its identifier as text) and "influence" includes effects via OnClick, OnChange, and Check, as well as Definition attributes.
inclusive
Boolean. By default FindObjects(influences: x)
does not include x
itself. When «inclusive» is true, it includesx
in its result. This also applies to parameters «influencedBy», «within», «withinAny», «contains» and «containsAny».
within
When you specify one or more modules, it searches only objects within those modules (and their submodules).
withinAny
Same as «within», but it also includes objects that are inside the specified module(s) only as a result of a module alias being inside the module.
contains
Searches among modules that contain any of the objects specified in «contains».
containsAny
Same as «contains», except that it also includes modules that contain an alias that contains the indicates object(s).
hasUserInput
When true, it returns only objects that have a user input node. When false, it returns only objects that have no user input.
hasUserOutput
When true, it returns only objects that have a user output node. When false, it returns only objects that have no user output.
hasInput
When true, it returns only objects that depend on at least one other variable. When false, returns objects that have no Inputs.
hasOutput
When true, it returns objects that have at least one Output variable or function. When false, returns only objects with no Outputs.
isLiteral
When true, it returns objects that contain only literals (explicit numbers, text, etc.) or are defined as a table with only literals in the cells, but contain no expressions, and refer to no variables other than the Index variables for the table dimensions.
Examples
Objects matching specific text
Find all objects having the text "Bacteria" anywhere within any text attribute (including Identifier, Units, Title, Description, Definition, and User-defined attributes). The match is case insensitive.
#FindObjects("Bacteria")
Find all objects with an identifier that starts with the prefix "Hydro_". The ^
character is the regular expression code for beginning-of-text, which prevents a match to "Cost_of_hydro_power".
#FindObjects("^Hydro_", Identifier)
You can equivalently quote the attribute name, or compute it:
Local att := "Identifier" Do #FindObjects("^Hydro_", att)
Find objects that have both the words "plant" and "animal" within its textual attributes. An object matches if each word appears in a different attribute, for example, "plant" in the Title, and "animal" in the Description. Notice that when using a Set Functions to combine criteria, you don't de-reference the result of FindObjects before passing it to the set function.
#SetUnion([FindObjects("plant"), FindObjects("animal")])
Find objects that have Units of "mph" or "miles per hour", which do not have a divide operator (/) in the Definition.
#SetDifference(FindObjects("(mph)|(miles per hour)", Units), FindObjects("/", Definition))
Find objects in which "lumina" appears in a textual attribute without being capitalized (it is a proper noun, so should be capitalized). It uses the regular expression control '\b
to match word-boundaries, so that words like "illumination" that contain the character sequence inside the word is not matched. The search is case-sensitive so that properly capitalized instances of "Lumina" are not included.
#FindObjects("\blumina\b", caseSensitive: True)
Find objects having the text "Power" in either the Identifier on Title. This uses named-calling syntax, but the positional syntax (with three parameters) would also work.
#FindObjects(regExp: "Power", attribute: Identifier, Title)
Find objects having the text "Dynamic" in any textual attribute other than the Definition.
#FindObjects("Dynamic", excludeAttribute]: Definition)
The variable Words
contains a vector of words, indexed by the index Word_idx
. The variable Attr_to_search
contains a list of attribute names, computed using Subset. Find objects having any of the indicated words in any of the indicated attributes. Only full words are matched (by use of the regular expression '\b'
), but the match is case insensitive. The full list of attributes from Attr_to_search
is passed to the «attribute» parameter by using Repeated parameter forwarding (the ...
).
#SetUnion(FindObjects('\b' & Words & '\b', attribute: ...Attr_to_search), Word_idx)
Building on the previous example, but passing Attr_to_search
without Repeated parameter forwarding, we end up with a list of results, one for each attribute, since array-abstraction kicks in on the list of attributes. So for example, if Attr_to_search
has the value ["Title", "Description", "Help"]
, the result is an array of three elements, the first having objects in whose Title attribute contains one of the words, the second cell has objects whose Description contains one of the words, etc. An important point here is that we cannot de-reference the result, because the result is collection of sets. Dereferencing would attempt to combine
SetUnion(FindObjects(Words, attribute: Attr_to_search), Word_idx)
To find all objects with no Definition, you will need to use the «value» parameter.
FindObjects(value: Null, attribute: Definition)
Objects of a certain type
Any of these three variations can be used to find all User-defined functions.
#FindObjects(class: Function)
#FindObjects(class: "Function")
#FindObjectsclass: Handle(Function))
Find all non-linked libraries.
#FindObjects(class: "Library")
Find all libraries, whether linked or non-linked.
#FindObjects(class: Library, LinkLibrary)
Find all modules or libraries. In this example, ModuleTypes
is a separate constant node in your model. Notice that Repeated Parameter Forwarding is used here to pass the full list of modules as a single call, without array-iterating over them.
Constant ModuleTypes := ["Module", "LinkModule", "Model", "Library", "LinkLibrary", "Form"]
#FindObjects(class: ...ModuleTypes)
You could also allow array-abstraction to iterate, returning the matches to each module type, and then combine the results using SetUnion.
#SetUnion(FindObjects(class: ModuleTypes), ModuleTypes)
Find all built-in system functions or system variables that contain the characters "sample" in the Identifier. Note that built-in objects are normally excluded from searches unless you specify the class explicitly.
#FindObjects("sample", Identifier, class: SysFunction, SysVar)
Find all non-module objects in your model. This uses the ModuleTypes
from a previous example a few lines above.
#FindObjects(excludeClass: ...ModuleTypes)
Objects with a certain value
Find all variables having a result value of 1.2 in any cell of the computed result. The search examines all mid- and sample- values that have been previously computed, but does not cause any variable to be computed in order to access its result. Any object having 1.2 in any cell of its result is returned.
#FindObjects(value: 1.2)
NaNs in the result
Find all variables having a NaN in any cell of the computed result. Take note that this only searches results that have been previously computed. It searches both mid-value and sample-value results. It is possible you might see a NaN a statistical view, such as for the standard deviation when there is fewer that 2 numbers in the sample, even though the sample contains no NaNs. In such a case, the object is not included, since the NaN must appear in the sample itself.
#FindObjects(value: NaN)
When searching for the origin of NaNs in your model, it can be useful to limit the search to variables upstream from the variable you are looking at with has NaNs in it. Suppose that variable is X
. You must use the Handle function when passing X
, otherwise you'd be passing the result of X
to the «influences» parameter.
#FindObjects(value: NaN, influences: Handle(X))
Finding upstream or downstream variables
Find all the objects (variables and user-defined functions) that influence Revenue
directly or indirectly. You must use the Handle function to specify the variable (or you can specify its textual name), otherwise it will evaluate Revenue
and try to use its result (which would cause an error, since it doesn't evaluate to a handle). The result does not include X
itself, unless it does depend on itself through a Dynamic or Iterate.
#FindObjects(influences: Handle(Revenue))
Find all objects that are upstream of variable Y
, but downstream from variable X
.
#FindObjects(influences: Handle(Y), influencedBy: Handle(X))
Find the objects that depend on X
and influence Y
, and include X
and Y
in the result.
#FindObjects(influences: Handle(Y), influencedBy: Handle(X), inclusive: true)
Find all variables in the same Dynamic loop at X
.
#FindObjects(influences: Handle(X), influencedBy: Handle(X))
Finding objects that use a function or variable
Find all variables that use the function DbQuery:
#FindObjects(outputOf: "DbQuery")
The following also finds all variables and functions that use the function DbQuery, but the variable containing this call to FindObjects will also be included in the result.
FindObjects(outputOf: Handle(DbQuery))
The search FindObjects("DbQuery")
would also find these variables, but it would also find objects where the text "DbQuery"
appears in comments, quotes, or in textual attributes like Description. The «outputOf» search criteria limits the results to cases where an expression makes use of the indicated object.
Find all variables that are immediate children of Gas_price
(e.g., that reference Gas_Price
in their definition).
FindObjects(outputOf: Handle(Gas_price))
Find all variables in the same dynamic loop as X
which have a Dynamic definition.
FindObjects(influences: X, influencedBy: X, inclusive: true, outputOf: Handle(Dynamic))
The inverse of «outputOf» is «inputOf». Find all immediate parents of X
.
FindObjects(inputOf: X)
Find all the system functions or system variables that are used by the variable X
.
FindObjects(inputOf: X, class: SysVar, SysFunction)
Finding objects by locations within module hierarchy
Find all the non-module objects inside the module Sensitivity_analysis
. This uses the constant ModuleTypes
that was defined earlier in the examples. This result includes all objects that are inside any sub-module of Sensitivity_analysis
, at any depth.
#FindObjects(within: Handle(Sensitivity_analysis), excludeClass: ...ModuleTypes)
Suppose there is a module named Power_generation
which is not inside the Sensitivity_analysis
module, but an alias of the Power_generation
model has been created and placed with the Sensitivity_analysis
module. The preceding search using «within» does not include the objects inside the alias module. Find all non-module objects inside Sensitivity_analysis
, or any of its submodules or alias submodules, at any depth.
#FindObjects(withinAny: Handle(Sensitivity_analysis), excludeClass: ...ModuleTypes)
Find all the parent and ancestor modules (not following aliased modules) of x
.
#FindObjects(contains: Handle(x))
Find all parent and ancestor modules, including module aliases and their parents, of x
.
#FindObjects(containsAny: Handle(x))
Find the common modules of X
and Y
. In other words, those modules that have both X
and Y
somewhere within their module hierarchy. X
and Y
may be in different modules.
#FindObjects(contains: X, Y)
Finding model inputs or outputs
Which variable do you consider to be model inputs? The most obvious would be those variables having user input nodes. You can find these using.
#FindObjects(hasUserInput: true)
You might consider an input to be a node with no parents.
#FindObjects(hasInput: false)
but Tables have parents (the indexes), even if all the cells are numbers. So you might want the objects that have only literals in their definitions (text, numbers, null), including tables. This would exclude a table having expressions in their definition or in their table cells.
#FindObjects(isLiteral: true)
Or maybe in addition to these criteria, a variable is only an input when it is actually used by another object.
#FindObjects(isLiteral: true, hasOutput: true)
In a symmetrical fashion, an output might be a variable that has a user output node.
#FindObjects(hasUserOutput: false)
or that has no children of its own.
#FindObjects(hasOutput: false)
Find the inputs that influence the result of Y
, using a concept that an input is either an object defined as a literal or table of literals, or is a variable with a user input node.
#SetUnion(FindObjects(hasUserInput: true, influences: Handle(Y)), FindObjects(isLiteral: true, influences: Handle(Y))
FoundSet to tag nodes on a Diagram
You can use the system variable Sys_FoundSet
to identify results from FindObjects (or any set of objects) by tagging their nodes with a magnifying glass icon in their Diagrams, and in the Outline view. You can also step through the variable using "Find Next" option from the Object menu, or press ctrl+G, to step through the variables. This can be very helpful while debugging to trace how one variable influences another across several diagrams, for example:
Sys_FoundSet
normally contains a list of the objects found from the last time you used the Find dialog. You can also assign a result from FindObjects to Sys_FoundSet
in a Button OnClick attribute. For example,
Sys_FoundSet := FindObjects(influencedBy: "Demand_growth_rate", influences: "Dollar_sales_by_prod", inclusive: true);
To show the magnifying glass tags, you must also set the system variable DepictFoundSetOnUI
to 1:
DepictFoundSetOnUI := 1
(If you make these assignments in a Typescript Window, you must enclose each assignment in parentheses, in line with Typescript syntax.)
History
Introduced in Analytica 5.0.
Enable comment auto-refresher
Marksmith