Beispiel #1
0
	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()
Beispiel #4
0
	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()