def choose_variables(self): """ Return all the selected variables, ensuring that their resources are valid. """ all_vars = sift(self.global_store.variables.values(), OutputVariable) vars = [var for var in all_vars if var.enabled and var.use_const and var.resource_name] missing_resources = [] unwritable_resources = [] for var in vars: try: if not self.global_store.resources[var.resource_name].writable: unwritable_resources.append(var.resource_name) except KeyError: missing_resources.append(var.resource_name) if missing_resources: MessageDialog(self, ', '.join(missing_resources), 'Missing resources').Show() if unwritable_resources: MessageDialog(self, ', '.join(unwritable_resources), 'Unwritable resources').Show() if missing_resources or unwritable_resources: return None return vars
def choose_variables(self): """ Return all the selected variables, ensuring that their resources are valid. """ all_vars = sift(self.global_store.variables.values(), OutputVariable) vars = [ var for var in all_vars if var.enabled and var.use_const and var.resource_name ] missing_resources = [] unwritable_resources = [] for var in vars: try: if not self.global_store.resources[var.resource_name].writable: unwritable_resources.append(var.resource_name) except KeyError: missing_resources.append(var.resource_name) if missing_resources: MessageDialog(self, ', '.join(missing_resources), 'Missing resources').Show() if unwritable_resources: MessageDialog(self, ', '.join(unwritable_resources), 'Unwritable resources').Show() if missing_resources or unwritable_resources: return None return vars
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 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()