def measurement(self, request, iteration): ''' sweep with 1d/2d/3d source measurements ''' from_product = pd.MultiIndex.from_product if request.param == 'scalar': frame = pd.DataFrame({'data': [1]}) #ref_index = pd.Int64Index(range(4), name='iteration') ref_index = pd.MultiIndex(levels=[range(4)], labels=[range(4)], names=['iteration']) ref_data = np.arange(4) elif request.param == 'vector': index = pd.Int64Index(range(2), name='x') frame = pd.DataFrame({'data': np.arange(1, 3, dtype=np.int64)}, index) ref_index = from_product([range(4), range(2)], names=['iteration', 'x']) ref_data = (np.arange(4)[:, np.newaxis]*np.arange(1, 3)).ravel() elif request.param == 'matrix': index = from_product([range(2), range(3)], names=['x', 'y']) frame = pd.DataFrame({'data': np.arange(6, dtype=np.int64)}, index) ref_index = from_product([range(4), range(2), range(3)], names=['iteration', 'x', 'y']) ref_data = (np.arange(4)[:, np.newaxis]*np.arange(6)).ravel() # save reference frame as attribute self.reference = pd.DataFrame({'data': np.array(ref_data, np.int64)}, index=ref_index) # generate measurement m = Function(lambda iteration: iteration*frame, [iteration], coordinates=[Parameter(name) for name in frame.index.names if name is not None], values=[Parameter('data')]) return Sweep(iteration, range(4), m)
def parameters(self): self.ps = [ Parameter('test{0}'.format(idx), value=idx) for idx in range(2) ] self.pN = Parameter('testN') self.pX = Parameter('invalid') return self.ps
def test_set_func(self): self.set_val = None def set_func(val): self.set_val = val p = Parameter('test', set_func=set_func) p.set(-1) assert self.set_val == -1
def test_getitem_parameter(self, keys_and_dict): ''' get value by key ''' keys, rd = keys_and_dict pX = Parameter('pX') p1 = Parameter(keys[0].name) # object different from keys[0] assert rd[keys[0]] == 0 with raises(KeyError): rd[pX] with raises(KeyError): rd[p1]
def buffer(self): index = pd.MultiIndex.from_product([range(2), range(2)], names=['x', 'y']) frame = pd.DataFrame({'z': range(4)}, index=index) self.pscale = Parameter('scale', value=1) self.source = Function(lambda scale: frame * scale, args=[self.pscale], coordinates=[Parameter('x'), Parameter('y')], values=[Parameter('z')]) return Buffer(self.source)
def test_popt_out(self, method): px = Parameter('x') popt_out = {px: 'c0'} # pass as arg to __init__ or assign to property if method == 'arg': measurement = self.klass(popt_out=popt_out, **self.kwargs()) elif method == 'property': measurement = self.klass(**self.kwargs()) measurement.popt_out = popt_out # run measurement() assert np.isclose(px.get(), 2.)
def measurement(self, request): args = [Parameter('foo', value=1), Parameter('bar', value=2)] if request.param == 'args': kwargs = {} elif request.param == 'kwargs': kwargs = dict(zip(['x', 'y'], args)) args = [] elif request.param == 'mixed': kwargs = {'y': args.pop()} coordinates = [] values = [Parameter('z1'), Parameter('z2')] return Function(self.function, args, kwargs, coordinates, values)
def function(self, reversed=False): def f(x, y): # skewed parabola centered at x=2, y=-1.25 z = (x - 2.)**2 + 2.*(y + 1.25)**2 items = [('positive', [z]), ('negative', [-z])] return pd.DataFrame.from_dict(OrderedDict(items[::-1] if reversed else items)) self.px = Parameter('x') self.py = Parameter('y') self.pp = Parameter('positive') self.pn = Parameter('negative') values = [self.pp, self.pn] return Function(f, [self.px, self.py], values=values[::-1] if reversed else values)
def test_inheritance(self): # check inheritance of coordinates m = ImplementedMeasurement('') m.coordinates.append(Parameter('Default', value=0)) m.coordinates.append(Parameter('True', value=1), inheritable=True) m.coordinates.append(Parameter('False', value=2), inheritable=False) m.measurements.append(WritingMeasurement('Default')) m.measurements.append(WritingMeasurement('True'), inherit_local_coords=True) m.measurements.append(WritingMeasurement('False'), inherit_local_coords=False) store = m() assert 'True' in store['/Default'].index.names assert 'Default' in store['/True'].index.names assert 'True' in store['/True'].index.names assert 'False' not in store['/True'].index.names assert 'True' not in store['/False'].index.names
class TestBuffer(MeasurementTests): @fixture def buffer(self): index = pd.MultiIndex.from_product([range(2), range(2)], names=['x', 'y']) frame = pd.DataFrame({'z': range(4)}, index=index) self.pscale = Parameter('scale', value=1) self.source = Function(lambda scale: frame * scale, args=[self.pscale], coordinates=[Parameter('x'), Parameter('y')], values=[Parameter('z')]) return Buffer(self.source) # run MeasurementTests against uninitialized and initialized buffers @fixture(params=[False, True], ids=['uninitialized', 'initialized']) def measurement(self, request, buffer): if request.param: buffer.writer() return buffer.reader def test_call(self, buffer): with raises(TypeError): buffer() def test_read_write(self, buffer): self.pscale.set(1) ref1 = self.source(output_data=True) buffer.writer() read1 = buffer.reader(output_data=True) assert ref1.equals(read1), 'buffer did not return same value as source' self.pscale.set(2) ref2 = self.source(output_data=True) assert not ref1.equals( ref2), 'source return did not change, test error' read2 = buffer.reader(output_data=True) assert ref1.equals(read2), 'buffer return affected by change of source' def test_multi_read(self, buffer): ''' assert that multiple readers can be inserted into the tree ''' ma = MeasurementArray(buffer.writer, buffer.reader, buffer.reader) ma() def test_multi_write(self, buffer): ''' assert that only one writer can be inserted into the tree ''' ma = MeasurementArray(buffer.writer, buffer.writer, buffer.reader) with raises(ValueError): ma()
def arg_factory(self, arg, type_): if type_ == 'measurement': return Constant(arg) elif type_ == 'parameter': return Parameter('arg', value=arg) elif type_ == 'const': return arg
def test_cache(self, pawg_factory, awgs, cache, pulse_kwargs_id, pulse_kwargs): if pulse_kwargs_id == 'Parameter': parameter = pulse_kwargs['kwarg'] else: parameter = Parameter('pkwarg') sw = Sweep(parameter, [1, 2, 1], pawg_factory(cache=cache)) frame = sw(output_data=True) for awg in awgs: if cache: if pulse_kwargs_id == 'Parameter': assert awg.seq_files[0] != awg.seq_files[1], \ 'Same file programmed despite parameter change.' assert frame['index'].values[0] != frame['index'].values[1] else: # incorrect use of cache by the user xfail( 'cache=True and pulse_func depends on variables not in kwargs.' ) assert awg.seq_files[0] == awg.seq_files[2], \ 'A new file was programmed instead of the cached one.' assert frame['index'].values[0] == frame['index'].values[2] else: assert len(set(awg.seq_files)) == 3, \ 'A previous file was reprogrammed but cache=False.' assert list(frame['index'].values) == list(range(3))
def pulse_kwargs(self, pulse_kwargs_id): if pulse_kwargs_id == 'const': return {'kwarg': 0} elif pulse_kwargs_id == 'Parameter': return {'kwarg': Parameter('pkwarg', value=0)} else: return {}
def test_MultiSweep(marg): ''' Test of MultiSweep assuming that it just returns nested Sweeps ''' px = Parameter('x') py = Parameter('y') m = CountingMeasurement() if marg == 'none': with raises(TypeError): MultiSweep(px, range(5), py, range(4)) return if marg == 'args': sw = MultiSweep(px, range(5), py, range(4), m) elif marg == 'kwargs': sw = MultiSweep(px, range(5), py, range(4), measurement=m) assert sw.coordinates.names() == ['x', 'y'] assert sw.measurements[0].coordinates .names() == ['y'] assert sw.measurements[0].measurements[0] == m
def test_coordinate_assign(self, m): # ParameterList is fully tested assert isinstance(m.coordinates, ParameterList) # assignment should leave coordinates intact m.coordinates = [Parameter('flux0')] assert isinstance(m.coordinates, ParameterList) self.test_coordinate_append(m)
def test_order(self, instrument): p = Parameter('p', get_func=lambda: instrument.get('power')) ctx = SetInstrument(instrument, 'power2', p, 'power', 10) with ctx: assert instrument.get('power2') == 0 ctx = SetInstrument(instrument, 'power', 0, 'power2', p) with ctx: assert instrument.get('power2') == 0
def test_substore(self): # test view into store and inherited coordinates m = ImplementedMeasurement(data_directory='Root') m.coordinates.append(Parameter('x', value=1.)) m.measurements.append(ImplementedMeasurement(data_directory='Sub')) m.measurements[0].measurements.append(WritingMeasurement('Node')) store = m() assert '/Sub/Node' in store assert 'x' in store['/Sub/Node'].index.names
def __init__(self, raises=None, raise_count=0, **kwargs): ''' A measurement that returns incrementing integers. Parameters: raises (Exception, optional) - Exception to raise when the counter reaches raise_count. raise_count (int, default 0) - Counter value that triggers the Exception. ''' super(CountingMeasurement, self).__init__(**kwargs) self.counter = Parameter('count', value=-1) self.prepare_count = 0 self.setup_count = 0 self.measure_count = 0 self.teardown_count = 0 self.values.append(self.counter) self.raises = raises self.raise_count = raise_count
def ranges(self, range_id): if range_id == 'one-const': return 'c0', range(3) elif range_id == 'two-const': return 'c0', range(3), 'c1', range(2) elif range_id == 'three-const': return 'c0', range(3), 'c1', range(2), 'c2', range(4) elif range_id == 'one-callable': return 'c0', lambda: range(3) elif range_id == 'one-parameter': return 'c0', Parameter('c0', value=range(3))
def test_equals(self): ''' test equals operator (with array data) ''' p0 = Parameter('p0') p0b = Parameter('p0') p1 = Parameter('p1') m0 = numpy.arange(50) m1 = numpy.ones((50, )) d0 = ParameterDict([(p0, m0)]) # not a dict assert d0 != [] # different length assert d0 != ParameterDict([]) # different data assert d0 != ParameterDict([(p0, m1)]) # different key assert d0 != ParameterDict([(p1, m0)]) # different key but with same name assert d0 != ParameterDict([(p0b, m0)]) # same keys and values, different object assert d0 == ParameterDict([(p0, m0)])
class CountingMeasurement(Measurement): def __init__(self, raises=None, raise_count=0, **kwargs): ''' A measurement that returns incrementing integers. Parameters: raises (Exception, optional) - Exception to raise when the counter reaches raise_count. raise_count (int, default 0) - Counter value that triggers the Exception. ''' super(CountingMeasurement, self).__init__(**kwargs) self.counter = Parameter('count', value=-1) self.prepare_count = 0 self.setup_count = 0 self.measure_count = 0 self.teardown_count = 0 self.values.append(self.counter) self.raises = raises self.raise_count = raise_count def _setup(self): self.setup_count += 1 def _prepare(self): self.prepare_count += 1 def _measure(self, **kwargs): self.measure_count += 1 self.counter.set(self.counter.get() + 1) if (self.raises is not None) and (self.counter.get() == self.raise_count): raise self.raises() frame = pd.DataFrame.from_dict( {self.counter.name: [self.counter.get()]}) self.store.append(frame) return frame def _teardown(self): self.teardown_count += 1
class TestMeasureAWGSweep(AWGSweepTests, MeasurementTests): #ranges, awgs, pulse_func, marker_func, pulse_kwargs, @fixture def pulse_kwargs_id(self, request): # multiple source instances are tested without this return None @fixture def source(self, pawg_factory, normalize): kwargs = { 'template_func': normalize.template_func } if normalize is not None else {} store = pawg_factory(**kwargs)() frame = store['/map'] if normalize is None: frame['data'] = list(range(len(frame))) else: frame['data'] = [-1, 1] + list(range(len(frame) - 2)) return Constant(frame) @fixture(params=[None, NormalizeAWG()], ids=['', 'normalize']) def normalize(self, request): pass @fixture def measurement(self, ranges, source, normalize): return MeasureAWGSweep(*ranges, source=source, normalize=normalize) @mark.parametrize('normalize', [NormalizeAWG()], ids=['normalize']) def test_normalize(self, measurement): frame = measurement(output_data=True) assert len(frame) assert all(frame['data'].values == list(range(len(frame)))) @AWGSweepTests.all_ranges @mark.parametrize('normalize', [None], ids=['']) def test_reshape(self, measurement, ranges): frame = measurement(output_data=True) print(frame) for column in frame.columns[:-1]: assert all(frame.index.get_level_values(column) == frame[column]) @mark.parametrize('segments', [5, Parameter('segments', value=5)], ids=['segments:int', 'segments:Parameter']) def test_segments(self, ranges, source, segments): cm = CaptureMeasurement(source) MeasureAWGSweep(*ranges, source=cm, segments=segments)() assert 'segments' in cm.kwargs assert cm.kwargs['segments'] == resolve_value(segments)
def test_link(self): p1 = Parameter('p1', value=1) p2 = Parameter('p2') lp = LinkedParameter(p1, p2) assert lp.parameters == (p1, p2) assert lp.name == p1.name assert lp.get() == 1 lp.set(2) assert (p1.get() == 2) and (p2.get() == 2)
def test_parameter_set(self, measurement): ''' check setting of .values and popt_out ''' # add a nested measurement that measures f0 in two different ways f0_out = Parameter('f0_out') pm = ParameterMeasurement(measurement.values['f0'], f0_out, name='pm') measurement.measurements.append(pm) measurement.popt_out = {f0_out: 'f0'} # run fitter store = measurement() ref_frame = store['/Fit'] frame = store['/pm'] # check for FittingMeasurement.values.set assert np.all(frame['f0'].values == ref_frame['f0']) # check for popt_out working assert np.all(frame['f0_out'].values == ref_frame['f0'])
def source(self, transposed=False, reversed=False, shape2=0): ''' Parameters: transposed - if True, index levels are y, x instead of x, y reversed - if True, columns are negative, positive instead of positive, negative shape2 - length of the third dimension. if 0, the output is two-dimensional. ''' if not transposed: self.sweepgen = MultiSweep else: self.sweepgen = lambda c0, r0, c1, r1, m, **kwargs: \ MultiSweep(c1, r1, c0, r0, m, **kwargs) function = self.function(reversed) if shape2: function = Sweep(Parameter('excess'), np.arange(shape2), function) return function
def __getattr__(self, pname): """ Return method or construct `Parameter` for instrument attribute `pname`. """ if pname in self._pnames: kwargs = {} kwargs['name'] = '{0}.{1}'.format(self._name, pname) kwargs['get_func'] = lambda: self.get(pname) kwargs['set_func'] = lambda value: self.set(pname, value) return Parameter(**kwargs) elif pname in self._fnames: function_spec = self._proxy.get_function_spec( self._remote_name, pname) if function_spec is not None: return lambda *args, **kwargs: self.call( pname, *args, **kwargs) raise AttributeError( 'Instrument {0} has no parameter or function "{1}". If you changed the FPGA app, then try update()' .format(self._name, pname))
def source(self, transposed=False, reversed=False, shape2=0): ''' Parameters: transposed - if True, index levels are y, x instead of x, y reversed - if True, columns are negative, positive instead of positive, negative shape2 - length of the third dimension. if 0, the output is two-dimensional. ''' function = self.function(reversed) if not transposed: px, py = (self.px, self.py) else: px, py = (self.py, self.px) if shape2: function = Sweep(Parameter('excess'), np.arange(shape2), function) inner_sw = Sweep(py, np.linspace(-4, 4, 9), function) outer_sw = Sweep(px, np.linspace(-4, 4, 9), inner_sw) return outer_sw
def test_sweep_average(self, measurement): measurement = Sweep(Parameter('iteration'), range(5), measurement) store = measurement() mframe = self.mframe(np.arange(0, 50, 10), np.arange(9, 50, 10)) assert store['/Counting'].reset_index(drop=True).equals(mframe)
def averages(self, request): if request.param == 'int': return 10 else: return Parameter('averages', value=10)
def iteration(): return Parameter('iteration')