Example Hardware Map Queries

The correct syntax when using HWM query objects is not necessarily intuitive, since it tries to bridge python-like syntax with SQL-like queries.

Once you understand the mechanics though, it because pretty trivial to construct arbitrarily complex queries. Below are some examples demonstrating most of what people will generally be trying to do. If none of these covers your circumstance, let me know (Joshua). This page in particular should be a resource that grows if need be.

What is a Query?

A query is a method of hardware map (hwm) objects. It can also refer to the object that method returns:

In [1]: import pydfmux

In [2]: session = pydfmux.load_session(open('mcgill/hardware_maps/mcgill_hwm_004/mcgill_hwm_complete.yaml','r'))

In [3]: hwm = session['hardware_map']

In [4]: bolos = hwm.query(pydfmux.Bolometer)

In [5]: bolos
Out[5]: <pydfmux.core.hardware_map.HWMQuery at 0x1104a42d0>

That query object is iterable, like a list of returns, but also has some special properties: in particular it knows about all of the methods of the objects contained.

In [6]: bolos.all()
Out[6]:
 [Wafer(u'arg1a').Bolometer(u'1A.1.X'),
  Wafer(u'arg1a').Bolometer(u'1A.1.Y'),
  Wafer(u'arg1a').Bolometer(u'1A.2.X'),
  Wafer(u'arg1a').Bolometer(u'1A.2.Y'),
  Wafer(u'arg1a').Bolometer(u'1A.3.X'),
  Wafer(u'arg1a').Bolometer(u'1A.3.Y'),
  Wafer(u'arg1a').Bolometer(u'1A.4.X'),
  Wafer(u'arg1a').Bolometer(u'1A.4.Y'),
  Wafer(u'arg1a').Bolometer(u'1A.5.X'),
  Wafer(u'arg1a').Bolometer(u'1A.5.Y'),
  Wafer(u'arg1a').Bolometer(u'1A.6.X'),
  Wafer(u'arg1a').Bolometer(u'1A.6.Y'),
  Wafer(u'arg1a').Bolometer(u'1A.7.X'),
  Wafer(u'arg1a').Bolometer(u'1A.7.Y'),
  Wafer(u'arg1a').Bolometer(u'1A.8.X'),
  Wafer(u'arg1a').Bolometer(u'1A.8.Y')]

In [7]: bolos[0]
Out[7]: Wafer(u'arg1a').Bolometer(u'1A.1.X')

In [8]: bolos[0].<tab>
 bolos[0].channel_map      bolos[0].name             bolos[0].state
 bolos[0].hwm              bolos[0].overbias         bolos[0].tune
 bolos[0].iceboard         bolos[0].readout_channel  bolos[0].wafer
 bolos[0].lc_channel       bolos[0].rfrac
 bolos[0].metadata         bolos[0].squid

In [9]: bolos.lc_channel
Out[9]:
 [LCBoard(u'LC001_A').LCChannel(1),
  LCBoard(u'LC001_A').LCChannel(2),
  LCBoard(u'LC001_A').LCChannel(3),
  LCBoard(u'LC001_A').LCChannel(4),
  LCBoard(u'LC001_B').LCChannel(1),
  LCBoard(u'LC001_B').LCChannel(2),
  LCBoard(u'LC001_B').LCChannel(3),
  LCBoard(u'LC001_B').LCChannel(4),
  LCBoard(u'LC001_C').LCChannel(1),
  LCBoard(u'LC001_C').LCChannel(2),
  LCBoard(u'LC001_C').LCChannel(3),
  LCBoard(u'LC001_C').LCChannel(4),
  LCBoard(u'LC001_D').LCChannel(1),
  LCBoard(u'LC001_D').LCChannel(2),
  LCBoard(u'LC001_D').LCChannel(3)]

 In [10]: bolos.overbias_and_null()
 2015-08-21 15:45:15 | INFO | overbias_and_null.py | overbias_and_null | STARTING: overbiasing on 1 modules
 .
 .
 .

All of pydfmux “runs on” query objects, in the sense that the core algorithms act using query objects. Often you will see the algorithms executed by calling methods of the object contained within query on the set of all objects contained in the query (bolos.overbias_and_null()).

So, a query object is the central object of pydfmux, it is important to know how to get and manipulate these objects.

Elements of Querying

When formulating a query, there are three primary ingredients:

  • query(pydfmux.OBJECT) specifies the type of object to be contained in the query returned.
  • filter(. . .) filters the contents based on attributes of the object, or any other joined object.
  • join(pydfmux.ANOTHEROBJECT) walks along the ORM map (Objects in a Dfmux Hardware Map.) to “join” objects together in order to filter by joined objects in addition to returned objects (covered in detail at the bottom of this section).

Filters

A query for Bolometers, filtered based on whether the “tuned” in the hardware map is “True”:

In [11]: bolos_all = hwm.query(pydfmux.Bolometer)

In [12]: all(bolos_all.tune)
Out[12]: False

In [13]: bolos_tune = hwm.query(pydfmux.Bolometer).filter(pydfmux.Bolometer.tune==True)

In [14]: all(bolos_tune.tune)
Out[14]: True

Note here that .filter is a method of the query object, so additional filters can be performed on the same query object:

In [15]: bolos_tune_trimmed = bolos_tune.filter(pydfmux.Bolometer.rfrac<0.9)

These could also have been done simultaneously as separate arguments to filter:

In [16]: bolos_tune_trimmed = hwm.query(pydfmux.Bolometer).filter(pydfmux.Bolometer.tune==True,
                                                                  pydfmux.Bolometer.rfrac<0.9)

Instead of justing using comparators in the filter (<, >, ==, etc) it can also be used to check for inclusion. Given a list of Bolometer names that I wish to tune separately, I query for bolometer whose names are in that list:

In [17]: special_bolos = hwm.query(pydfmux.Bolometer).filter(pydfmux.Bolometer.name.in_(['1A.5.Y', '1A.6.X']))

In [18]: special_bolos.name
Out[18]: [u'1A.5.Y', u'1A.6.X']

Note that the “in” is NOT a separate word (as you might expect from pure python). There is no space between “Bolometer.name.” and “in_”. The underscore is also important.

If, alternatively, I have a list of bolometers I wish to exclude, I can perform a negation by prepending the filter line with a tidle (~).

In [19]: good_bolos = hwm.query(pydfmux.Bolometer).filter(~pydfmux.Bolometer.name.in_(['1A.5.Y', '1A.6.X']))

In [20]: '1A.5.Y' in good_bolos.name
Out[20]: False

Warning

This is different from python and not intuitive, so I want to emphasize it. To negate a filtering parameter, instead of using “not” as you would in python, it should be prepended with a tilde (~).

Joins

What if you want to query for Bolometers, but filter based on the transimpedance of the SQUIDs they are attached to?

This will not work:

In [21]: bolos = hwm.query(pydfmux.Bolometer).filter(pydfmux.SQUID.transimpedance>300) # Bad Query

Because “transimpedance” is an attribute of Bolometers, and this hasn’t shown the query how to get from Bolometers to SQUIDs. That is the role of join.

In order to get from SQUID to Bolometer we need to step through the ChannelMapping object (see Objects in a Dfmux Hardware Map.).

A correct query will look like:

In [22]: bolos = y['hardware_map'].query(pydfmux.Bolometer).join(pydfmux.ChannelMapping,
                                                                 pydfmux.SQUID)\
                                                           .filter(pydfmux.SQUID.transimpedance>200)

Another example: To query SQUIDs that are controlled by Mezzanine 014, there are two different paths from the SQUID object to the MGMEZZ04 object:

In [23]: squids = y['hardware_map'].query(pydfmux.SQUID).join(pydfmux.SQUIDModule,
                                                              pydfmux.SQUIDController,
                                                              pydfmux.MGMEZZ04)\
                                                        .filter(pydfmux.MGMEZZ04.serial=='008')

In [24]: squids = y['hardware_map'].query(pydfmux.SQUID).join(pydfmux.ChannelMapping,
                                                              pydfmux.ReadoutChannel,
                                                              pydfmux.ReadoutModule,
                                                              pydfmux.MGMEZZ04)\
                                                        .filter(pydfmux.MGMEZZ04.serial=='008')

The second query will only work if there actually exist channel mappings between that SQUID and a readout channel. This happens in the CSV file that is part of the hardware map, and is therefore not guaranteed to be present for every SQUID. The first query, on the other hand, makes no such assumptions, and is thus the safer choice.

Note that, once items have been joined, any of them may be filtered on. So, in the example above, I can query for SQUIDs attached to Mezzanine 008, Module 1 like so:

In [25]: squids = y['hardware_map'].query(pydfmux.SQUID).join(pydfmux.SQUIDModule,
                                                              pydfmux.SQUIDController,
                                                              pydfmux.MGMEZZ04)\
                                                        .filter(pydfmux.MGMEZZ04.serial=='008',
                                                                pydfmux.SQUIDModule.module==1)

ORM Plot Resource

The interconnections between these structures are shown in Objects in a Dfmux Hardware Map..

../_images/objects.svg

Paths to walk along the ORM.