-
Notifications
You must be signed in to change notification settings - Fork 2
SearchingForNodes
There are essentially two modes of searching: a "global" search of an entire node scope, ns.Search()
, and a search over subtrees, ns.nodename.search()
. Both work pretty much the same way as far as search criteria are concerned.
The ns.Search() function is at the bottom of all searches. It has the following signature:
- {{{Search(name=None,class_name=None,tags=None, * return_names=False, subtree=None) }}}
The name and class_name arguments allow you to search by node name and node class.
- Strings are interpreted as regular expressions using Python's re module. (See regex reference or regex how-to for documentation.) Note that regex matching, not searching is used, and a '$' character is always added on automatically:
-
ns.Search(name='Z.*')
finds all nodes whose names begin with "Z" -
ns.Search(name='Z')
finds the exact name "Z"
-
- Specifying both name and class_name is a logical-AND:
-
ns.Search(name='Z.*',class_name='MeqParm')
finds all MeqParms with names starting with "Z".
-
- And of course you can use parentheses and the "|" regex character to do logical-ORs:
-
ns.Search(name='(Z|D).*',class_name='MeqParm')
finds all MeqParms with names starting with "Z" or "D".
-
A node can be tagged with an arbitrary set of strings. This is done by specifying tags= x,y,... when creating the node. Tags are just another field of the init-record and are ignored by the node itself, but they're special in that you can do a search on them. When a list of strings (or a single string) is supplied as the tags argument to ns.Search(), it will search for nodes whose set of tags includes ALL of the specified ones.
-
ns.Search(tags='tec')
finds all nodes with a "tec" tag. -
ns.Search(tags=('mim','solvable'))
finds all nodes that are tagged with BOTH "mim" and "solvable". -
Regexes are allowed, so
ns.Search(tags=('mim','s.*'))
finds all node that have a "mim" tag, and a tag starting with "s". Tag search can be combined with name and class_name, as a logical-AND: -
ns.Search(tags='gain',class_name='MeqParm')
finds all MeqParms with a "gain" tag. For some example searches, see WH/contrib/OMS/demo-iono-cal.py.
-
return_names is
False
if you want Search() to return a list of node objects, orTrue
if you want a list of node names. - If subtree is
None
, search is conducted over the entire node scope. Otherwise you can specify a single node or a list of nodes to restrict the search to one specific subtree (or a set of subtrees).
Node family is a new term for an old concept. A "family" is essentially a set of nodes differing only in qualifiers. For example, if you have created a series of nodes as ns.Z(x,y)
, then:
-
the family of "Z" consists of all initialized nodes whose names start with "Z"
-
the family of "Z:A" consists of all initialized nodes whose names start with "Z:A" The "initialized" bit is important. Your script may refer to
nz.Z
itself without qualifiers, but that doesn't make "Z" a real node. On the other hand, you may have explicitly initializedns.Z
with something, as well as all thens.Z(x,y)
nodes. -
In the former case "Z" is not initialized, so the family "Z" consists of the Z(x,y) nodes only.
-
In the latter case "Z" is initialized, so the family "Z" consists of "Z" itself, plus all the Z(x,y)'s. A node's family may be obtained by calling family() on the node. This will return a list of node objects. In the example above:
-
ns.Z.family()
returns all the Z(x,y)'s, and also Z itself, if initialized. -
ns.Z('A').family()
returns all the Z('A',y)'s. You can also get a family by callingns.FindFamily('Z')
.
Subtree search is important in, e.g., the following scenario. Say you have a function that creates the trees for a bunch of Jones matrices:
-
Z = compute_zeta_jones(...)
AndZ
then refers to a whole set of nodes that need to be qualified with, e.g., source name and station. The question is, how does the caller determine all solvable parameters that have gone into the Z's?
Subtree search makes this easy. Firstly, your functions should follow some tagging convention. Say, e.g., all solvables should be tagged with a "solvable" tag. Then, the caller can do a subtree search:
-
Z.search(tags="solvable");
This searches the subtrees of the entire "Z" family for nodes tagged as "solvable".
To be precise, each node object has a search() method that (by default) does an ns.Search()
operation on all the subtrees in that node's family. So
-
ns.Z.search(...)
is actually equivalent to -
ns.Search(subtree=ns.Z.family(),...)
but more concise. A variation of this: -
ns.Z.search(no_family=True,...)
is actually equivalent to -
ns.Search(subtree=[ns.Z],...)
i.e. does the search on that specific node's subtree only (of course ns.Z then needs to be an actual node, otherwise the search returns an empty list.)