Skip to content
Gijs Molenaar edited this page Feb 13, 2014 · 5 revisions

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.

Global Search of the NodeScope

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) }}}

Searching by name and/or class

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".

Searching by tags

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.

Search options

  • return_names is False if you want Search() to return a list of node objects, or True 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 Families

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 initialized ns.Z with something, as well as all the ns.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 calling ns.FindFamily('Z').

Subtree Search

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(...) And Z 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.)

Clone this wiki locally