I'm trying to reuse some of the existing code in other experiments, which are simply the combination of the existing experiments in a row, possibly with extra channels to be added in parallel. The straightforward idea that comes to my mind is class inheritance. For example, I implement all the experiment sequences that may be used in an experient as a method in a base class Base which is the child class of EnvExperiment.

class Base(EnvExperiment):
    def build(self):
            ...
    def seq1(self):
            ...
    def seq2(self):
            ...
    def seq3(self):
           ...
      ...

Then once I need to implement a new experiment, I simply inherit it like

from artiq.experiment import *
from Base import Base

class SampleExperiment(Base):
    def run(self):
        self.seq1()
        delay(1*ms)
        self.seq3()

However, it seems that the management system of ARTIQ won't allow me to do so. If I run the experiment via artiq_run, it returns ValueError: More than one experiment found in module.

I wonder if there exists any simple way to realize the elegant reuse. I know I can combine sequences in a single class, but as more than one people in my lab need to write experiment code, it's not a good idea to modify the same class. It's obviously not elegant either to copy the code since the parameters in a single sequence may change and I won't be bothered to mind the detail when I just need to combine them.

Thanks in advance.

Maybe there's a way to define a dummy class with dummy devices, in which I can define some methods that describe the certain behavior I need as an experiment step, while the dummy class itself does nothing. Only when I specify the correspondance between the dummy devices and the real devices, the class can be found and executed by the ARTIQ management system.

After going through the source code of ARTIQ management system, I've worked out a solution, which is unexpectedly simple: just del Base after the definition of SampleExperiment. (Or just import Base instead of from Base import Base)

5 days later

Not sure mine is the most elegant solution, but the current approach I use is to define classes derived from HasEnvironment that implement a standard "subroutine" (e.g. a class StdCool for cooling, StdDetect for detection, one for state initialization, etc.). To make use of these, a given experiment (e.g. a Ramsey experiment) is derived from EnvExperiment and creates instances of these classes in the build() stage for whichever subroutines it needs.

The general idea is

`
from artiq.experiment import *
import std_tools #my package of code I often need to use

class SomeExperiment(EnvExperiment):

def build(self):
    #do stuff
    self.cool = std_tools.StdCool(self)
    #do more stuff



@kernel
def run(self):
    #do stuff
    self.cool.go()         #implements the cooling sequence to laser cool the ions
    #do more stuff

`

An advantage of this is a given experiment only needs to load modules for the subroutines it needs, as opposed to inheriting from a Base class in which case every sequence will always be inherited, even if the given experiment doesn't need some of them. On the other hand, I suppose one could just create multiple different variations of bases classes fo different types of experiments.

Definitely interested in other people's approaches as well.

6 days later

Your approach is valid, artiq_run just needs to know which of the two executable experiments should be taken.
Try artiq_run -c SampleExperiment

Starting those experiments from the Dashboard should be no problem.

14 days later

Bit late of a response, but I just wanted to share how we handle code reuse for our systems. We basically set up ARTIQ projects with "system code" which contains routines that are re-used over various experiments. In essence separating code shared between experiments of experiment-specific procedures. This whole code organization is supported by our own software framework: https://gitlab.com/duke-artiq/dax . There is a link to an example project that shows a toy example of how we organize code using our framework. Maybe it could be interesting to take a look at!

    lriesebos Thanks for sharing such an awesome project. Actually I've taken a glance at the Dax months ago and thought it was an project providing high level api (quantum gate operation) over ARTIQ, which is not suitable for us at this stage. I should spend some time on Dax to see if I can migrate from our existing sloppy codes to it.

      isaac sure, no problem! I have recently tried to improve the readme a bit, but if unclear, DAX basically has 5 components at this moment.

      1. Modular system organization
      2. Functional simulator
      3. Scanning experiment tools
      4. Automatic scheduling tools
      5. Gate-level API stuff

      These components can be used independent from each other or all together if you want. So the modular system organization part might be most in your interest at this time based on this thread.

      I have to admit that the wiki's are often a bit outdated, but I am happy to assist if you have any questions. The example project might also be worth checking out to get a basic idea of how to do modular system organization.