def read(self): """ Take measurements. """ measurements = [None] * len(self.measurement_resources) thrs = [] for i, (name, resource) in enumerate(self.measurement_resources): if resource is not None: def save_callback(value, i=i): measurements[i] = value if self.read_callback is not None: self.read_callback(i, value) thr = Thread(target=self.read_resource, args=(name, resource, save_callback)) thrs.append(thr) thr.daemon = True thr.start() for thr in thrs: thr.join() if self.data_callback is not None: if self.first_time_point is None: cur_time = 0 self.first_time_point = time() else: cur_time = time() - self.first_time_point self.data_callback(cur_time, tuple(flatten(self.current_values)), tuple(measurements)) return self.condition
def read(self): """ Take measurements. """ measurements = [None] * len(self.measurement_resources) thrs = [] for i, (name, resource) in enumerate(self.measurement_resources): if resource is not None: def save_callback(value, i=i): measurements[i] = value if self.read_callback is not None: self.read_callback(i, value) thr = Thread(target=self.read_resource, args=(name, resource, save_callback)) thrs.append(thr) thr.daemon = True thr.start() for thr in thrs: thr.join() if self.data_callback is not None: if self.first_time_point is None: cur_time = 0 self.first_time_point = time() else: cur_time = time() - self.first_time_point self.data_callback(cur_time, tuple(flatten(self.current_values)), tuple(measurements)) return self.condition
def __init__(self, resources, variables, num_items, measurement_resources, measurement_variables, condition_resources=[], condition_variables=[], pulse_config=None, continuous=False): self.resources = resources self.variables = variables self.num_items = num_items self.measurement_resources = measurement_resources self.measurement_variables = measurement_variables #TODO: Instead of flattening, make use of the group ordering for quicker access self.condition_resources = [ cond_tuple for cond_tuple in flatten(condition_resources) ] self.condition_variables = condition_variables self.pulse_config = pulse_config self.continuous = continuous # The callbacks should be set before calling run(), if necessary. self.data_callback, self.close_callback, self.write_callback, self.read_callback = [ None ] * 4 self.general_exception_handler = None self.resource_exception_handler = None self.devices_configured = False self.current_f = None self.item = -1 self.paused = False self.pause_lock = Condition() self.last_continuous = False self.done = False self.aborting = False self.abort_fatal = False self.sweep_start_time = time() self.first_time_point = None self.orders = [vars[0].order for vars in self.variables] self.orders.reverse() self.condition_orders = [ group[0].order for group in self.condition_variables ] self.conditional_wait = 0 self.order_periods = None
def load_values(f): """ Load data points from a file. The values in the file must either be comma separated, line-wise, or a combination of the two. For example: 1.0,2.0,3.0 4.0,5.0 6.0 would be interpreted as [1.0, 2.0, 3.0, 4.0, 5.0, 6.0] """ reader = csv.reader(f) # Ignore blank lines. return [float(x) for x in flatten(reader) if not x.isspace()]
def load_values(f): """ Load data points from a file. The values in the file must either be comma separated, line-wise, or a combination of the two. For example: 1.0,2.0,3.0 4.0,5.0 6.0 would be interpreted as [1.0, 2.0, 3.0, 4.0, 5.0, 6.0] """ reader = csv.reader(f) # Ignore blank lines. return [float(x) for x in flatten(reader) if not x.isspace()]
def __init__(self, resources, variables, num_items, measurement_resources, measurement_variables, condition_resources=[], condition_variables=[], pulse_config=None, continuous=False): self.resources = resources self.variables = variables self.num_items = num_items self.measurement_resources = measurement_resources self.measurement_variables = measurement_variables #TODO: Instead of flattening, make use of the group ordering for quicker access self.condition_resources = [cond_tuple for cond_tuple in flatten(condition_resources)] self.condition_variables = condition_variables self.pulse_config = pulse_config self.continuous = continuous # The callbacks should be set before calling run(), if necessary. self.data_callback, self.close_callback, self.write_callback, self.read_callback = [None] * 4 self.general_exception_handler = None self.resource_exception_handler = None self.devices_configured = False self.current_f = None self.item = -1 self.paused = False self.pause_lock = Condition() self.last_continuous = False self.done = False self.aborting = False self.abort_fatal = False self.sweep_start_time = time() self.first_time_point = None self.orders = [vars[0].order for vars in self.variables] self.orders.reverse() self.condition_orders = [group[0].order for group in self.condition_variables] self.conditional_wait = 0 self.order_periods = None
def OnBeginCapture(self, evt=None): # Prevent accidental double-clicking. self.start_button.Disable() def enable_button(): sleep(1) wx.CallAfter(self.start_button.Enable) thr = Thread(target=enable_button) thr.daemon = True thr.start() all_variables = [var for var in list(self.global_store.variables.values()) if var.enabled] output_variables = sift(all_variables, OutputVariable) input_variables = [var for var in sift(all_variables, InputVariable) if var.resource_name != ''] condition_variables = sift(all_variables, ConditionVariable) if not output_variables: output_variables.append(OutputVariable(order=0, name='<Dummy>', enabled=True)) output_variables, num_items = sort_output_variables(output_variables) condition_variables = sort_condition_variables(condition_variables) resource_names = [tuple(var.resource_name for var in group) for group in output_variables] measurement_resource_names = [var.resource_name for var in input_variables] condition_resource_names = [tuple(set(flatten([var.resource_names for var in group]))) for group in condition_variables] continuous = self.continuous_checkbox.Value missing_resources = set() unreadable_resources = set() unwritable_resources = set() missing_devices = set() pulse_program = self.global_store.pulse_program if pulse_program is not None: pulse_program = pulse_program.with_resources try: pulse_program.generate_waveforms(dry_run=True) except PulseError as e: MessageDialog(self, '\n'.join(e[0]), 'Pulse program error', monospace=True).Show() return except Exception as e: MessageDialog(self, str(e), 'Pulse program error').Show() return pulse_awg, pulse_oscilloscope = None, None pulse_channels = {} try: pulse_awg = self.global_store.devices[pulse_program.awg].device if pulse_awg is None: raise KeyError except KeyError: missing_devices.add(pulse_program.awg) else: # Gather used channel numbers. pulse_channels = dict((k, v) for k, v in list(pulse_program.output_channels.items()) if v is not None) actual_channels = list(range(1, len(pulse_awg.channels))) invalid_channels = [k for k, v in list(pulse_channels.items()) if v not in actual_channels] if invalid_channels: MessageDialog(self, 'Invalid channels for: {0}'.format(', '.join(invalid_channels)), 'Invalid channels').Show() return try: pulse_oscilloscope = self.global_store.devices[pulse_program.oscilloscope].device if pulse_oscilloscope is None: raise KeyError except KeyError: missing_devices.add(pulse_program.oscilloscope) try: pulse_config = PulseConfiguration(pulse_program, pulse_channels, pulse_awg, pulse_oscilloscope) except TypeError as e: MessageDialog(self, str(e), 'Device configuration error').Show() return else: pulse_config = None resources = [] for group in resource_names: group_resources = [] for name in group: if name == '': group_resources.append((str(len(resources)), None)) elif name not in self.global_store.resources: missing_resources.add(name) else: resource = self.global_store.resources[name] if resource.writable: group_resources.append((name, resource)) else: unwritable_resources.add(name) resources.append(tuple(group_resources)) measurement_resources = [] measurement_units = [] for name in measurement_resource_names: if name not in self.global_store.resources: missing_resources.add(name) else: resource = self.global_store.resources[name] if resource.readable: measurement_resources.append((name, resource)) measurement_units.append(resource.display_units) else: unreadable_resources.add(name) condition_resources = [] for group in condition_resource_names: group_resources = [] for name in group: if name not in self.global_store.resources: missing_resources.add(name) else: resource = self.global_store.resources[name] if resource.readable: group_resources.append((name, resource)) else: #the name may already have been put here by the loop assigning #to measurement_resources if name not in unreadable_resources: unreadable_resources.add(name) condition_resources.append(tuple(group_resources)) mismatched_resources = [] for (res_name, resource), var in zip(flatten(resources), flatten(output_variables)): if resource is None: continue if resource.units is not None: if not (var.type == 'quantity' and resource.verify_dimensions(var.units, exception=False, from_string=True)): mismatched_resources.append((res_name, var.name)) else: if var.type not in ['float', 'integer']: mismatched_resources.append((res_name, var.name)) for items, msg in [ (missing_resources, 'Missing resources'), (unreadable_resources, 'Unreadable resources'), (unwritable_resources, 'Unwritable resources'), (missing_devices, 'Missing devices')]: if items: MessageDialog(self, ', '.join('"{0}"'.format(x) for x in sorted(items)), msg).Show() if mismatched_resources: MessageDialog(self, ', '.join('Mismatched resource type for resource name {0} with variable name {1}'.format(x[0], x[1]) for x in mismatched_resources), 'Mismatched resources').Show() if (missing_resources or unreadable_resources or unwritable_resources or missing_devices or mismatched_resources): return # Check that all the condition arguments are compatible with one another. for cvar in flatten(condition_variables): # Get a condition. for cond in cvar.conditions: value1 = cond.arg1 value2 = cond.arg2 resource1 = None resource2 = None # If working with resources, use their values as the values, and make the resource available if cond.type1 == 'resource name': resource1 = [resource for (name, resource) in flatten(condition_resources) if name == cond.arg1][0] value1 = resource1.value if cond.type2 == 'resource name': resource2 = [resource for (name, resource) in flatten(condition_resources) if name == cond.arg2][0] value2 = resource2.value # Check if the other argument is in the allowed values if hasattr(resource1,'allowed_values') and resource1.allowed_values is not None: if value2 not in resource1.allowed_values: MessageDialog(self, 'In the condition {0}, {1} is not in allowed_values of {2}.'.format(cond, value2, cond.arg1),'Condition error').Show() return if hasattr(resource2,'allowed_values') and resource2.allowed_values is not None: if value1 not in resource2.allowed_values: MessageDialog(self, 'In the condition {0}, {1} is not in allowed_values of {2}.'.format(cond, value1, cond.arg2),'Condition error').Show() return # Check if units agree. if resource1 is not None and resource1.units is not None: try: value1.assert_dimensions(value2) except ValueError: MessageDialog(self, 'In the condition {0}, {1} does not have a dimension.'.format(cond, value2),'Condition error').Show() return except IncompatibleDimensions: MessageDialog(self, 'In the condition {0}, {1} and {2} do not have matching dimensions.'.format(cond, value1, value2),'Condition error').Show() return if resource2 is not None and resource2.units is not None: try: value2.assert_dimensions(value1) except ValueError: MessageDialog(self, 'In the condition {0}, {1} does not have a dimension.'.format(cond, value1),'Condition error').Show() return except IncompatibleDimensions: MessageDialog(self, 'In the condition {0}, {1} and {2} do not have matching dimensions.'.format(cond, value1, value2),'Condition error').Show() return exporting = False if self.export_enabled.Value: dir = self.directory_browse_button.GetValue() # YYYY-MM-DD_HH-MM-SS.csv name = '{0:04}-{1:02}-{2:02}_{3:02}-{4:02}-{5:02}.csv'.format(*localtime()) if not dir: MessageDialog(self, 'No directory selected.', 'Export path').Show() return if not os.path.isdir(dir): MessageDialog(self, 'Invalid directory selected', 'Export path').Show() return file_path = os.path.join(dir, name) if os.path.exists(file_path): MessageDialog(self, file_path, 'File exists').Show() return # Everything looks alright, so open the file. export_file = open(file_path, 'w') export_csv = csv.writer(export_file) exporting = True # Show the path in the GUI. self.last_file_name.Value = file_path # Write the header. export_csv.writerow(['Time (s)'] + ['{0.name} ({0.units})'.format(var) if var.units is not None else var.name for var in flatten(output_variables)] + ['{0.name} ({1})'.format(var, units) if units is not None else var.name for var, units in zip(input_variables, measurement_units)]) self.capture_dialogs += 1 dlg = DataCaptureDialog(self, resources, output_variables, num_items, measurement_resources, input_variables, condition_resources, condition_variables, pulse_config, continuous=continuous) dlg.SetMinSize((500, -1)) for name in measurement_resource_names: wx.CallAfter(pub.sendMessage, 'data_capture.start', name=name) # Export buffer. max_buf_size = 10 buf = [] buf_lock = Lock() def flush(): export_csv.writerows(buf) export_file.flush() while buf: buf.pop() def data_callback(cur_time, values, measurement_values): for name, value in zip(measurement_resource_names, measurement_values): wx.CallAfter(pub.sendMessage, 'data_capture.data', name=name, value=value) # Extract values out of quantities, since the units have already been taken care of in the header. values = [x.original_value if hasattr(x, 'original_value') else x for x in values] measurement_values = [x.original_value if hasattr(x, 'original_value') else x for x in measurement_values] if exporting: with buf_lock: buf.append([cur_time] + values + measurement_values) if len(buf) >= max_buf_size: flush() def close_callback(): self.capture_dialogs -= 1 if exporting: with buf_lock: flush() export_file.close() for name in measurement_resource_names: wx.CallAfter(pub.sendMessage, 'data_capture.stop', name=name) dlg.data_callback = data_callback dlg.close_callback = close_callback dlg.Show() dlg.start()
def testProper(self): """ Testing everything that there is to test along the happy path: nested and parallel variables measurements dwell time """ res_bufs = [[], [], [], []] measurement_counts = [0] * 2 def setter(i, value): res_bufs[i].append(value) def getter(i): measurement_counts[i] += (-1) ** i return measurement_counts[i] dwell_time = Quantity(50, 'ms') # Output. res0 = Resource(setter=partial(setter, 0)) res0.units = 'cm-1' res1 = Resource(setter=partial(setter, 1)) res2 = Resource(setter=partial(setter, 2)) res3 = Resource(setter=partial(setter, 3)) var0 = OutputVariable(name='Var 0', order=2, enabled=True, const=0.0) var0.config = LinSpaceConfig(-1.0, -2.0, 2) var0.smooth_steps = 2 var0.smooth_from, var0.smooth_to, var0.smooth_transition = [True] * 3 var0.type = 'quantity' var0.units = 'cm-1' var1 = OutputVariable(name='Var 1', order=1, enabled=True, const=-1.0) var1.config = LinSpaceConfig(1.0, 4.0, 4) var1.smooth_steps = 3 var1.smooth_from, var1.smooth_to, var1.smooth_transition = [True] * 3 var2 = OutputVariable(name='Var 2', order=1, enabled=True, const=1.23, use_const=True) var3 = OutputVariable(name='Var 3', order=1, enabled=True, const=-9.0, wait=str(dwell_time)) var3.config = LinSpaceConfig(-1.0, 2.0, 4) var3.smooth_steps = 2 var3.smooth_from, var3.smooth_to, var3.smooth_transition = True, True, False var4 = OutputVariable(name='Var 4', order=3, enabled=True, const=-20.0) var4.config = LinSpaceConfig(-10.0, 20, 1) var4.smooth_steps = 2 var4.smooth_from = True # Input. meas_res0 = Resource(getter=partial(getter, 0)) meas_res1 = Resource(getter=partial(getter, 1)) meas0 = InputVariable(name='Meas 0') meas1 = InputVariable(name='Meas 1') vars, num_items = sort_output_variables([var0, var1, var2, var3, var4]) ctrl = sweep.SweepController([(('Res 2', res2),), (('Something', None),), (('Res 0', res0),), (('Res 1', res1), ('Res 3', res3))], vars, num_items, [('Meas res 0', meas_res0), ('Meas res 1', meas_res1)], [meas0, meas1]) # Callback verification buffers. actual_values = [] actual_measurement_values = [] actual_writes = [] actual_reads = [] closed = [0] # Callbacks. def data_callback(cur_time, values, measurement_values): actual_values.append(values) actual_measurement_values.append(measurement_values) ctrl.data_callback = data_callback def close_callback(): closed[0] += 1 ctrl.close_callback = close_callback def write_callback(pos, i, value): actual_writes.append((pos, i, value)) ctrl.write_callback = write_callback def read_callback(i, value): actual_reads.append((i, value)) ctrl.read_callback = read_callback # Let it run. start_time = time() ctrl.run() elapsed_time = time() - start_time expected_time = num_items * dwell_time.value assert expected_time < elapsed_time, 'Took {0} s, expected at least {1} s.'.format(elapsed_time, expected_time) expected_res1 = [1.0, 2.0, 3.0, 4.0] expected_res2 = [-1.0, 0.0, 1.0, 2.0] expected_inner_writes = list(flatten(((3, 0, x), (3, 1, x - 2.0)) for x in [1.0, 2.0, 3.0, 4.0])) expected_writes = [(0, 0, 1.23), (1, 0, -10.0)] + list(flatten([(2, 0, x)] + expected_inner_writes for x in [Quantity(x, 'cm-1') for x in [-1.0, -2.0]])) eq_(res_bufs, [ [Quantity(x, 'cm-1') for x in [0.0, -1.0, -1.0, -2.0, -2.0, 0.0]], [-1.0, 0.0, 1.0] + expected_res1 + [4.0, 2.5, 1.0] + expected_res1 + [4.0, 1.5, -1.0], [1.23], [-9.0, -1.0] + expected_res2 + expected_res2 + [2.0, -9.0], ]) eq_(measurement_counts, [8, -8]) eq_(actual_values, [(1.23, -10.0, x, y, y - 2.0) for x in [Quantity(x, 'cm-1') for x in [-1.0, -2.0]] for y in [1.0, 2.0, 3.0, 4.0]]) eq_(actual_measurement_values, [(x, -x) for x in xrange(1, 9)]) eq_(actual_writes, expected_writes) eq_(actual_reads, list(flatten(((0, x), (1, -x)) for x in xrange(1, 9)))) eq_(closed, [1])
def testConditionsSweep(self): """ Tests a setup with condition variables and output variables. Similar to testProper, but with conditions mixed in. """ res_bufs = [[], [], [], []] measurement_counts = [0] * 2 def setter(i, value): res_bufs[i].append(value) def getter(i): measurement_counts[i] += (-1) ** i return measurement_counts[i] dwell_time = Quantity(50, 'ms') # Output. res0 = Resource(setter=partial(setter, 0)) res0.units = 'cm-1' res1 = Resource(setter=partial(setter, 1)) res2 = Resource(setter=partial(setter, 2)) res3 = Resource(setter=partial(setter, 3)) var0 = OutputVariable(name='Var 0', order=2, enabled=True, const=0.0) var0.config = LinSpaceConfig(-1.0, -2.0, 2) var0.smooth_steps = 2 var0.smooth_from, var0.smooth_to, var0.smooth_transition = [True] * 3 var0.type = 'quantity' var0.units = 'cm-1' var1 = OutputVariable(name='Var 1', order=1, enabled=True, const=-1.0) var1.config = LinSpaceConfig(1.0, 4.0, 4) var1.smooth_steps = 3 var1.smooth_from, var1.smooth_to, var1.smooth_transition = [True] * 3 var2 = OutputVariable(name='Var 2', order=1, enabled=True, const=1.23, use_const=True) var3 = OutputVariable(name='Var 3', order=1, enabled=True, const=-9.0, wait=str(dwell_time)) var3.config = LinSpaceConfig(-1.0, 2.0, 4) var3.smooth_steps = 2 var3.smooth_from, var3.smooth_to, var3.smooth_transition = True, True, False var4 = OutputVariable(name='Var 4', order=3, enabled=True, const=-20.0) var4.config = LinSpaceConfig(-10.0, 20, 1) var4.smooth_steps = 2 var4.smooth_from = True # Condition variables. ## Resources used for checking the conditions. iters = [cycle([0,1]), cycle([0,1,2]), cycle([0,-1,-2])] def cres_getter(i): return iters[i].next() cres0 = Resource('cres0', getter=partial(cres_getter,0)) cres1 = Resource('cres1', getter=partial(cres_getter,1)) cres2 = Resource('cres2', getter=partial(cres_getter,2)) condition_resources = [(('cres0',cres0),),(('cres1',cres1),('cres2',cres2),)] cond0 = Condition('resource name','integer','cres0','==',1) cond1 = Condition('resource name','integer','cres1','==',2) cond2 = Condition('resource name','integer','cres2','==',-2) cvar0 = ConditionVariable(name='cvar0',order=0,enabled=True,wait=str(dwell_time), resource_names=['cres0',],conditions=[cond0]) cvar1 = ConditionVariable(name='cvar1',order=1,enabled=True,wait=str(dwell_time), resource_names=['cres1',],conditions=[cond1]) cvar2 = ConditionVariable(name='cvar2',order=1,enabled=True,wait=str(dwell_time), resource_names=['cres2',],conditions=[cond2]) # Input. meas_res0 = Resource(getter=partial(getter, 0)) meas_res1 = Resource(getter=partial(getter, 1)) meas0 = InputVariable(name='Meas 0') meas1 = InputVariable(name='Meas 1') vars, num_items = sort_output_variables([var0, var1, var2, var3, var4]) cvars = sort_condition_variables([cvar0,cvar1,cvar2]) ctrl = sweep.SweepController([(('Res 2', res2),), (('Something', None),), (('Res 0', res0),), (('Res 1', res1), ('Res 3', res3))], vars, num_items, [('Meas res 0', meas_res0), ('Meas res 1', meas_res1)], [meas0, meas1], condition_resources, cvars) # Callback verification buffers. actual_values = [] actual_measurement_values = [] actual_writes = [] actual_reads = [] closed = [0] # Callbacks. def data_callback(cur_time, values, measurement_values): actual_values.append(values) actual_measurement_values.append(measurement_values) ctrl.data_callback = data_callback def close_callback(): closed[0] += 1 ctrl.close_callback = close_callback def write_callback(pos, i, value): actual_writes.append((pos, i, value)) ctrl.write_callback = write_callback def read_callback(i, value): actual_reads.append((i, value)) ctrl.read_callback = read_callback # Let it run. start_time = time() ctrl.run() elapsed_time = time() - start_time expected_time = num_items * dwell_time.value assert expected_time < elapsed_time, 'Took {0} s, expected at least {1} s.'.format(elapsed_time, expected_time) expected_res1 = [1.0, 2.0, 3.0, 4.0] expected_res2 = [-1.0, 0.0, 1.0, 2.0] expected_inner_writes = list(flatten(((3, 0, x), (3, 1, x - 2.0)) for x in [1.0, 2.0, 3.0, 4.0])) expected_writes = [(0, 0, 1.23), (1, 0, -10.0)] + list(flatten([(2, 0, x)] + expected_inner_writes for x in [Quantity(x, 'cm-1') for x in [-1.0, -2.0]])) eq_(res_bufs, [ [Quantity(x, 'cm-1') for x in [0.0, -1.0, -1.0, -2.0, -2.0, 0.0]], [-1.0, 0.0, 1.0] + expected_res1 + [4.0, 2.5, 1.0] + expected_res1 + [4.0, 1.5, -1.0], [1.23], [-9.0, -1.0] + expected_res2 + expected_res2 + [2.0, -9.0], ]) eq_(measurement_counts, [24, -24]) # Construct predicted actual values. expected_actual_values = [] for x in [Quantity(x, 'cm-1') for x in [-1.0, -2.0]]: for y in [1.0, 2.0, 3.0, 4.0]: # We append twice since the 0th order condition will create an extra measurement # for every non_conditionally based measurement expected_actual_values.append((1.23, -10.0, x, y, y - 2.0)) expected_actual_values.append((1.23, -10.0, x, y, y - 2.0)) # If were at the end of order 1, we append 4 more times to have a total of 6 # This is because in the condition checking stage, we require the 0th order condition # and the 1st order conditions to all be true. So, cycling through entries in [0,1] # and [0,1,2], it will take a total of 6 condition checks to get 1 in [0,1], and 2 in # [0,1,2]. if y == 4: expected_actual_values.append((1.23, -10.0, x, y, y - 2.0)) expected_actual_values.append((1.23, -10.0, x, y, y - 2.0)) expected_actual_values.append((1.23, -10.0, x, y, y - 2.0)) expected_actual_values.append((1.23, -10.0, x, y, y - 2.0)) eq_(actual_values, expected_actual_values) eq_(actual_measurement_values, [(x, -x) for x in xrange(1, 25)]) eq_(actual_writes, expected_writes) eq_(actual_reads, list(flatten(((0, x), (1, -x)) for x in xrange(1, 25)))) eq_(closed, [1])
def OnBeginCapture(self, evt=None): # Prevent accidental double-clicking. self.start_button.Disable() def enable_button(): sleep(1) wx.CallAfter(self.start_button.Enable) thr = Thread(target=enable_button) thr.daemon = True thr.start() all_variables = [var for var in self.global_store.variables.values() if var.enabled] output_variables = sift(all_variables, OutputVariable) input_variables = [var for var in sift(all_variables, InputVariable) if var.resource_name != ''] if not output_variables: output_variables.append(OutputVariable(order=0, name='<Dummy>', enabled=True)) output_variables, num_items = sort_variables(output_variables) resource_names = [tuple(var.resource_name for var in group) for group in output_variables] measurement_resource_names = [var.resource_name for var in input_variables] continuous = self.continuous_checkbox.Value missing_resources = set() unreadable_resources = set() unwritable_resources = set() missing_devices = set() pulse_program = self.global_store.pulse_program if pulse_program is not None: pulse_program = pulse_program.with_resources try: pulse_program.generate_waveforms(dry_run=True) except PulseError as e: MessageDialog(self, '\n'.join(e[0]), 'Pulse program error', monospace=True).Show() return except Exception as e: MessageDialog(self, str(e), 'Pulse program error').Show() return pulse_awg, pulse_oscilloscope = None, None pulse_channels = {} try: pulse_awg = self.global_store.devices[pulse_program.awg].device if pulse_awg is None: raise KeyError except KeyError: missing_devices.add(pulse_program.awg) else: # Gather used channel numbers. pulse_channels = dict((k, v) for k, v in pulse_program.output_channels.items() if v is not None) actual_channels = range(1, len(pulse_awg.channels)) invalid_channels = [k for k, v in pulse_channels.items() if v not in actual_channels] if invalid_channels: MessageDialog(self, 'Invalid channels for: {0}'.format(', '.join(invalid_channels)), 'Invalid channels').Show() return try: pulse_oscilloscope = self.global_store.devices[pulse_program.oscilloscope].device if pulse_oscilloscope is None: raise KeyError except KeyError: missing_devices.add(pulse_program.oscilloscope) try: pulse_config = PulseConfiguration(pulse_program, pulse_channels, pulse_awg, pulse_oscilloscope) except TypeError as e: MessageDialog(self, str(e), 'Device configuration error').Show() return else: pulse_config = None resources = [] for group in resource_names: group_resources = [] for name in group: if name == '': group_resources.append((str(len(resources)), None)) elif name not in self.global_store.resources: missing_resources.add(name) else: resource = self.global_store.resources[name] if resource.writable: group_resources.append((name, resource)) else: unwritable_resources.add(name) resources.append(tuple(group_resources)) measurement_resources = [] measurement_units = [] for name in measurement_resource_names: if name not in self.global_store.resources: missing_resources.add(name) else: resource = self.global_store.resources[name] if resource.readable: measurement_resources.append((name, resource)) measurement_units.append(resource.display_units) else: unreadable_resources.add(name) mismatched_resources = [] for (res_name, resource), var in zip(flatten(resources), flatten(output_variables)): if resource is None: continue if resource.units is not None: if not (var.type == 'quantity' and resource.verify_dimensions(var.units, exception=False, from_string=True)): mismatched_resources.append((res_name, var.name)) else: if var.type not in ['float', 'integer']: mismatched_resources.append((res_name, var.name)) for items, msg in [ (missing_resources, 'Missing resources'), (unreadable_resources, 'Unreadable resources'), (unwritable_resources, 'Unwritable resources'), (missing_devices, 'Missing devices')]: if items: MessageDialog(self, ', '.join('"{0}"'.format(x) for x in sorted(items)), msg).Show() if mismatched_resources: MessageDialog(self, ', '.join('{0}/{1}'.format(x[0], x[1]) for x in mismatched_resources), 'Mismatched resources').Show() if (missing_resources or unreadable_resources or unwritable_resources or missing_devices or mismatched_resources): return exporting = False if self.export_enabled.Value: dir = self.directory_browse_button.GetValue() # YYYY-MM-DD_HH-MM-SS.csv name = '{0:04}-{1:02}-{2:02}_{3:02}-{4:02}-{5:02}.csv'.format(*localtime()) if not dir: MessageDialog(self, 'No directory selected.', 'Export path').Show() return if not os.path.isdir(dir): MessageDialog(self, 'Invalid directory selected', 'Export path').Show() return file_path = os.path.join(dir, name) if os.path.exists(file_path): MessageDialog(self, file_path, 'File exists').Show() return # Everything looks alright, so open the file. export_file = open(file_path, 'w') export_csv = csv.writer(export_file) exporting = True # Show the path in the GUI. self.last_file_name.Value = file_path # Write the header. export_csv.writerow(['Time (s)'] + ['{0.name} ({0.units})'.format(var) if var.units is not None else var.name for var in flatten(output_variables)] + ['{0.name} ({1})'.format(var, units) if units is not None else var.name for var, units in zip(input_variables, measurement_units)]) self.capture_dialogs += 1 dlg = DataCaptureDialog(self, resources, output_variables, num_items, measurement_resources, input_variables, pulse_config, continuous=continuous) dlg.SetMinSize((500, -1)) for name in measurement_resource_names: wx.CallAfter(pub.sendMessage, 'data_capture.start', name=name) # Export buffer. max_buf_size = 10 buf = [] buf_lock = Lock() def flush(): export_csv.writerows(buf) export_file.flush() while buf: buf.pop() def data_callback(cur_time, values, measurement_values): for name, value in zip(measurement_resource_names, measurement_values): wx.CallAfter(pub.sendMessage, 'data_capture.data', name=name, value=value) # Extract values out of quantities, since the units have already been taken care of in the header. values = [x.original_value if hasattr(x, 'original_value') else x for x in values] measurement_values = [x.original_value if hasattr(x, 'original_value') else x for x in measurement_values] if exporting: with buf_lock: buf.append([cur_time] + values + measurement_values) if len(buf) >= max_buf_size: flush() def close_callback(): self.capture_dialogs -= 1 if exporting: with buf_lock: flush() export_file.close() for name in measurement_resource_names: wx.CallAfter(pub.sendMessage, 'data_capture.stop', name=name) dlg.data_callback = data_callback dlg.close_callback = close_callback dlg.Show() dlg.start()
def testProper(self): """ Testing everything that there is to test along the happy path: nested and parallel variables measurements dwell time """ res_bufs = [[], [], [], []] measurement_counts = [0] * 2 def setter(i, value): res_bufs[i].append(value) def getter(i): measurement_counts[i] += (-1)**i return measurement_counts[i] dwell_time = Quantity(50, 'ms') # Output. res0 = Resource(setter=partial(setter, 0)) res0.units = 'cm-1' res1 = Resource(setter=partial(setter, 1)) res2 = Resource(setter=partial(setter, 2)) res3 = Resource(setter=partial(setter, 3)) var0 = OutputVariable(name='Var 0', order=2, enabled=True, const=0.0) var0.config = LinSpaceConfig(-1.0, -2.0, 2) var0.smooth_steps = 2 var0.smooth_from, var0.smooth_to, var0.smooth_transition = [True] * 3 var0.type = 'quantity' var0.units = 'cm-1' var1 = OutputVariable(name='Var 1', order=1, enabled=True, const=-1.0) var1.config = LinSpaceConfig(1.0, 4.0, 4) var1.smooth_steps = 3 var1.smooth_from, var1.smooth_to, var1.smooth_transition = [True] * 3 var2 = OutputVariable(name='Var 2', order=1, enabled=True, const=1.23, use_const=True) var3 = OutputVariable(name='Var 3', order=1, enabled=True, const=-9.0, wait=str(dwell_time)) var3.config = LinSpaceConfig(-1.0, 2.0, 4) var3.smooth_steps = 2 var3.smooth_from, var3.smooth_to, var3.smooth_transition = True, True, False var4 = OutputVariable(name='Var 4', order=3, enabled=True, const=-20.0) var4.config = LinSpaceConfig(-10.0, 20, 1) var4.smooth_steps = 2 var4.smooth_from = True # Input. meas_res0 = Resource(getter=partial(getter, 0)) meas_res1 = Resource(getter=partial(getter, 1)) meas0 = InputVariable(name='Meas 0') meas1 = InputVariable(name='Meas 1') vars, num_items = sort_output_variables([var0, var1, var2, var3, var4]) ctrl = sweep.SweepController([(('Res 2', res2), ), (('Something', None), ), (('Res 0', res0), ), (('Res 1', res1), ('Res 3', res3))], vars, num_items, [('Meas res 0', meas_res0), ('Meas res 1', meas_res1)], [meas0, meas1]) # Callback verification buffers. actual_values = [] actual_measurement_values = [] actual_writes = [] actual_reads = [] closed = [0] # Callbacks. def data_callback(cur_time, values, measurement_values): actual_values.append(values) actual_measurement_values.append(measurement_values) ctrl.data_callback = data_callback def close_callback(): closed[0] += 1 ctrl.close_callback = close_callback def write_callback(pos, i, value): actual_writes.append((pos, i, value)) ctrl.write_callback = write_callback def read_callback(i, value): actual_reads.append((i, value)) ctrl.read_callback = read_callback # Let it run. start_time = time() ctrl.run() elapsed_time = time() - start_time expected_time = num_items * dwell_time.value assert expected_time < elapsed_time, 'Took {0} s, expected at least {1} s.'.format( elapsed_time, expected_time) expected_res1 = [1.0, 2.0, 3.0, 4.0] expected_res2 = [-1.0, 0.0, 1.0, 2.0] expected_inner_writes = list( flatten( ((3, 0, x), (3, 1, x - 2.0)) for x in [1.0, 2.0, 3.0, 4.0])) expected_writes = [(0, 0, 1.23), (1, 0, -10.0)] + list( flatten([(2, 0, x)] + expected_inner_writes for x in [Quantity(x, 'cm-1') for x in [-1.0, -2.0]])) eq_(res_bufs, [ [Quantity(x, 'cm-1') for x in [0.0, -1.0, -1.0, -2.0, -2.0, 0.0]], [-1.0, 0.0, 1.0] + expected_res1 + [4.0, 2.5, 1.0] + expected_res1 + [4.0, 1.5, -1.0], [1.23], [-9.0, -1.0] + expected_res2 + expected_res2 + [2.0, -9.0], ]) eq_(measurement_counts, [8, -8]) eq_(actual_values, [(1.23, -10.0, x, y, y - 2.0) for x in [Quantity(x, 'cm-1') for x in [-1.0, -2.0]] for y in [1.0, 2.0, 3.0, 4.0]]) eq_(actual_measurement_values, [(x, -x) for x in xrange(1, 9)]) eq_(actual_writes, expected_writes) eq_(actual_reads, list(flatten( ((0, x), (1, -x)) for x in xrange(1, 9)))) eq_(closed, [1])
def testConditionsSweep(self): """ Tests a setup with condition variables and output variables. Similar to testProper, but with conditions mixed in. """ res_bufs = [[], [], [], []] measurement_counts = [0] * 2 def setter(i, value): res_bufs[i].append(value) def getter(i): measurement_counts[i] += (-1)**i return measurement_counts[i] dwell_time = Quantity(50, 'ms') # Output. res0 = Resource(setter=partial(setter, 0)) res0.units = 'cm-1' res1 = Resource(setter=partial(setter, 1)) res2 = Resource(setter=partial(setter, 2)) res3 = Resource(setter=partial(setter, 3)) var0 = OutputVariable(name='Var 0', order=2, enabled=True, const=0.0) var0.config = LinSpaceConfig(-1.0, -2.0, 2) var0.smooth_steps = 2 var0.smooth_from, var0.smooth_to, var0.smooth_transition = [True] * 3 var0.type = 'quantity' var0.units = 'cm-1' var1 = OutputVariable(name='Var 1', order=1, enabled=True, const=-1.0) var1.config = LinSpaceConfig(1.0, 4.0, 4) var1.smooth_steps = 3 var1.smooth_from, var1.smooth_to, var1.smooth_transition = [True] * 3 var2 = OutputVariable(name='Var 2', order=1, enabled=True, const=1.23, use_const=True) var3 = OutputVariable(name='Var 3', order=1, enabled=True, const=-9.0, wait=str(dwell_time)) var3.config = LinSpaceConfig(-1.0, 2.0, 4) var3.smooth_steps = 2 var3.smooth_from, var3.smooth_to, var3.smooth_transition = True, True, False var4 = OutputVariable(name='Var 4', order=3, enabled=True, const=-20.0) var4.config = LinSpaceConfig(-10.0, 20, 1) var4.smooth_steps = 2 var4.smooth_from = True # Condition variables. ## Resources used for checking the conditions. iters = [cycle([0, 1]), cycle([0, 1, 2]), cycle([0, -1, -2])] def cres_getter(i): return iters[i].next() cres0 = Resource('cres0', getter=partial(cres_getter, 0)) cres1 = Resource('cres1', getter=partial(cres_getter, 1)) cres2 = Resource('cres2', getter=partial(cres_getter, 2)) condition_resources = [(('cres0', cres0), ), ( ('cres1', cres1), ('cres2', cres2), )] cond0 = Condition('resource name', 'integer', 'cres0', '==', 1) cond1 = Condition('resource name', 'integer', 'cres1', '==', 2) cond2 = Condition('resource name', 'integer', 'cres2', '==', -2) cvar0 = ConditionVariable(name='cvar0', order=0, enabled=True, wait=str(dwell_time), resource_names=[ 'cres0', ], conditions=[cond0]) cvar1 = ConditionVariable(name='cvar1', order=1, enabled=True, wait=str(dwell_time), resource_names=[ 'cres1', ], conditions=[cond1]) cvar2 = ConditionVariable(name='cvar2', order=1, enabled=True, wait=str(dwell_time), resource_names=[ 'cres2', ], conditions=[cond2]) # Input. meas_res0 = Resource(getter=partial(getter, 0)) meas_res1 = Resource(getter=partial(getter, 1)) meas0 = InputVariable(name='Meas 0') meas1 = InputVariable(name='Meas 1') vars, num_items = sort_output_variables([var0, var1, var2, var3, var4]) cvars = sort_condition_variables([cvar0, cvar1, cvar2]) ctrl = sweep.SweepController([(('Res 2', res2), ), (('Something', None), ), (('Res 0', res0), ), (('Res 1', res1), ('Res 3', res3))], vars, num_items, [('Meas res 0', meas_res0), ('Meas res 1', meas_res1)], [meas0, meas1], condition_resources, cvars) # Callback verification buffers. actual_values = [] actual_measurement_values = [] actual_writes = [] actual_reads = [] closed = [0] # Callbacks. def data_callback(cur_time, values, measurement_values): actual_values.append(values) actual_measurement_values.append(measurement_values) ctrl.data_callback = data_callback def close_callback(): closed[0] += 1 ctrl.close_callback = close_callback def write_callback(pos, i, value): actual_writes.append((pos, i, value)) ctrl.write_callback = write_callback def read_callback(i, value): actual_reads.append((i, value)) ctrl.read_callback = read_callback # Let it run. start_time = time() ctrl.run() elapsed_time = time() - start_time expected_time = num_items * dwell_time.value assert expected_time < elapsed_time, 'Took {0} s, expected at least {1} s.'.format( elapsed_time, expected_time) expected_res1 = [1.0, 2.0, 3.0, 4.0] expected_res2 = [-1.0, 0.0, 1.0, 2.0] expected_inner_writes = list( flatten( ((3, 0, x), (3, 1, x - 2.0)) for x in [1.0, 2.0, 3.0, 4.0])) expected_writes = [(0, 0, 1.23), (1, 0, -10.0)] + list( flatten([(2, 0, x)] + expected_inner_writes for x in [Quantity(x, 'cm-1') for x in [-1.0, -2.0]])) eq_(res_bufs, [ [Quantity(x, 'cm-1') for x in [0.0, -1.0, -1.0, -2.0, -2.0, 0.0]], [-1.0, 0.0, 1.0] + expected_res1 + [4.0, 2.5, 1.0] + expected_res1 + [4.0, 1.5, -1.0], [1.23], [-9.0, -1.0] + expected_res2 + expected_res2 + [2.0, -9.0], ]) eq_(measurement_counts, [24, -24]) # Construct predicted actual values. expected_actual_values = [] for x in [Quantity(x, 'cm-1') for x in [-1.0, -2.0]]: for y in [1.0, 2.0, 3.0, 4.0]: # We append twice since the 0th order condition will create an extra measurement # for every non_conditionally based measurement expected_actual_values.append((1.23, -10.0, x, y, y - 2.0)) expected_actual_values.append((1.23, -10.0, x, y, y - 2.0)) # If were at the end of order 1, we append 4 more times to have a total of 6 # This is because in the condition checking stage, we require the 0th order condition # and the 1st order conditions to all be true. So, cycling through entries in [0,1] # and [0,1,2], it will take a total of 6 condition checks to get 1 in [0,1], and 2 in # [0,1,2]. if y == 4: expected_actual_values.append((1.23, -10.0, x, y, y - 2.0)) expected_actual_values.append((1.23, -10.0, x, y, y - 2.0)) expected_actual_values.append((1.23, -10.0, x, y, y - 2.0)) expected_actual_values.append((1.23, -10.0, x, y, y - 2.0)) eq_(actual_values, expected_actual_values) eq_(actual_measurement_values, [(x, -x) for x in xrange(1, 25)]) eq_(actual_writes, expected_writes) eq_(actual_reads, list(flatten(((0, x), (1, -x)) for x in xrange(1, 25)))) eq_(closed, [1])