Hi All,

I am trying to follow the inheritance discussion here

https://forum.m-labs.hk/d/291-how-to-elegantly-reuse-the-experiment-code/7 but it is a bit old and incomplete.

and here

https://forum.m-labs.hk/d/296-changing-parameters-of-the-experiment

but the discussions are a bit old.

Given a test class (basic task) inside of file (basic_func1.py)
`

from artiq.experiment import *
import numpy as np


class Basic_Task(EnvExperiment):
"""basic things"""
def build(self):

    self.delay= 50*us
    self.setattr_device("core")
    self.setattr_device("sampler0")
    
    self.setattr_argument("n_samples", NumberValue(precision=0, 
                                                           step=1,scale=1))
        
   
    
    
@kernel
def run(self):
    
    
    self.core.reset()

    self.core.break_realtime()
    self.sampler0.init()

`

I would like to have another file (basic_inherit.py) import this class and then do something

`

from artiq.experiment import *
import numpy as np
import basic_func1
class Inherit_Basic(EnvExperiment):
"""Inherit Tester"""
def build(self):
    self.delay= 50*us #The sampling rate/ effective delay rate between commands
    # self.integration = 15*ms
    
    
    self.setattr_argument("integration", NumberValue(unit = "ms"
                                                     ,step=1))


    desired_samples = self.integration / self.delay
           
    self.sample = basic_func1.Basic_Task(self)
    

    self.setattr_device("core")
   
    print(self.n_samples)
    print(integration)
    
@kernel
def run(self):
    l=1

`

A basic example would be I want to define an integration time and then let the sampler measure for that integration time with however many samples are appropriate for the sampling rate without having to think about it.

1.) desired_samples = self.integration/self.delay seems to break the basic_inherit.py compatibility with the dashboard. Why? What I mean is that the file will not appear in the repository when scanning the available files unless this is commented out. When I try to ask what type self.integration is it reports back "Class Float" but this is not reported here https://m-labs.hk/artiq/manual/compiler.html as a valid type.

2.) How to pass the desired_samples = self.integration/self.delay into the self.sample instance ? I can do self.sample.n_samples = desired_samples but this feels cobbled together. I can force this to work by adding a build(self,n_samples) to the Basic_Task and then commenting out the setattr but this breaks the base module functionality.

3.) Is there a file where experiment attributes get dumped as a log? I inspected the results files but don't see a parameters file anywhere and I would generally prefer to see this logged as metadata.

Best,
Travis

    pyquest

    1. This happens because self.integration is defined via setattr_argument(), and its value is still None during the build() phase (when the experiment is being compiled or scanned). You should move the computation to the run() method, where self.integration is guaranteed to be initialized.

    2. A better approach is to treat the other file as a helper experiment solely for code reuse. You can achieve this by using the HasEnvironment class, which was also suggested in the referenced discussions.

    3. Seems like you can use datasets here, since it saves data in HDF5 format, which you can read separately or reuse in experiments (see Load HDF5 option in the experiment window). Additionally, setting persist=True will save the data in dataset_db.pyon for persistence across runs.

    See sample implementation:

    class Basic_Task(HasEnvironment):
        def build(self):
            self.delay= 50*us
            self.setattr_device("core")
            self.setattr_device("sampler0")
    
        @kernel
        def init_sampler(self):
            self.core.reset()
            self.core.break_realtime()
            self.sampler0.init()
    from basic_func1 import Basic_Task
    
    
    class Inherit_Basic(EnvExperiment):
        """Inherit Tester"""
        def build(self):
            self.setattr_device("core")
            self.setattr_argument("integration", NumberValue(unit = "ms", step=1))
            self.basic_task = Basic_Task(self)
            self.basic_task.build()
    
        @kernel
        def run(self):
            desired_samples = int(self.integration / self.basic_task.delay)
    
            self.set_dataset("integration_time", self.integration, persist=True)
            self.set_dataset("desired_samples", desired_samples, persist=True)
            self.basic_task.init_sampler()