atomiq.components package

The atomiq components are a mechanism to put the complexity of the experimental setup into a configuration and to allow to work with the setup at a higher abstraction level. The key ideas behind it are:

  • Have abstract, generic classes to represent different types of lab equipment (e.g. RFSource, DAC, AOM, Coil, Laser, etc)

  • Derive more specific classes from the generic ones. For example a channel of the Sinara Urukul is an RFSource but also a standalone AOM driver that is controlled by analog voltages is an RFSource. Thus, both, UrukulChannel and VoltageControlledRFSource inherit from RFSource.

  • Allow to reference other components in a component definition and recursively build all need components.

These ideas allow to move hardware specific information (like what devices are used and what device is plugged to which other device) into a configuration and to work with generic software objects that represent the actual hardware in the lab (like AOMs, Coils, Lasers, etc). It allows to define your experiment hardware in a simple dictionary and to dynamically link them together.

To get the idea, lets start with a simple example:

components = {}

# Add core stuff
components.update({
    "log": {
        "classname": "atomiq.components.basics.log.KernelLogger"
    }
})
# Add low level Sinara hardware
components.update({
    "kasli0": {
        "classname": "atomiq.components.sinara.Kasli",
        "arguments": {}
    },
    "urukul0": {
        "classname": "atomiq.components.sinara.Urukul",
        "arguments": {
            "cpld": "@urukul0_cpld"
        }
    }
})

# Add low Sinara DIOs
components.update({
    "ttl_test": {
        "classname": "atomiq.components.sinara.DioOutput",
        "arguments": {
            "kasli": "&kasli0",
            "ttl": "@led0"
        }
    }
})

# Add DDS channels
components.update({
    "dds_cooler": {
        "classname": "atomiq.components.sinara.UrukulChannel",
        "arguments": {
            "urukul": "&urukul0",
            "device": "@urukul0_ch0",
            "ttl": "@ttl_urukul0_sw0"
        }
    }
})

# Add AOMs
components.update({
    "aom_cooler": {
        "classname": "atomiq.components.optoelectronics.lightmodulator.AOM",
        "arguments": {
            "rfsource": "&dds_cooler",
            "switch": "&dds_cooler",
            "center_freq": 80e6,
            "bandwidth": 40e6,
            "switching_delay": 30e-9,
            "order": 1,
            "passes": 2
        }
    }
})

Each entry in the components dict is identified by a name that can be chosen to your liking.

Note

Since the component dict is flat, it might make sense to think about a proper naming scheme like <component_type>_<component_name> (e.g. aom_cooler, pd_repumper, coil_north, dds_cooler, etc.).

Every component needs to define a classname which defines the class the software object should have. Atomiq automatically builds these objects from the defined class, if you define that you require them in your experiment code. The arguments field takes the parameters that are needed to create the object. Look for the constructor method of the defined class to find what arguments are required/supported. These arguments are the basic means of adding default configuration for your components and to interconnect them.

Typically atomiq components rely on other components to do their job. It is thus necessary to reference to other components when writing the configuration for a certain component. Such interconnections between components are provided by starting an argument either with "&" (which refers to another component) or with "@" with refers to a device in your ARTIQ device_db.py. When creating the objects from the configuration, atomiq detects these references and recursively builds the components required by the component you need.

Warning

Please note that a restart of your ARTIQ master is required if you change your components definition since the device_db is only read upon starting the master.

Once you defined your components you can request atomiq to build it for you by adding it to the class-level components list of your experiment class

Atomiq comes with a lot of the most used classes already. See the following list to see what exists.

atomiq.components.build_object_from_device_db(parent, object_id)[source]
atomiq.components.build_object(classname, arg_dict)[source]
class atomiq.components.ComponentFactory[source]

Bases: object

static produce(name, parent)[source]

Subpackages

Submodules