def get_station(): # Create a station cryo_station = Station() # Associate the instruments with the station for instrument in setup_instruments(): cryo_station.add_component(instrument) # Send the station to the user return cryo_station
def get_station(): # Create a station magnetism_station = Station() # Get the associated instruments for instrument in setup_instruments(): magnetism_station.add_component(instrument) # Give the user the station return magnetism_station
def fill_station_zerodim(param_meas): station = Station() allinstr=qc.instrument.base.Instrument._all_instruments for key,val in allinstr.items(): instr = qc.instrument.base.Instrument.find_instrument(key) station.add_component(instr) measparstring = "" for parameter in param_meas: station.add_component(parameter) measparstring += parameter.name + ',' return measparstring
def take_buffer_keysight(self): """ takes a frequency sweep, not setting any values on the hardware """ from qcodes import Station station = Station() station.add_component(self.vna) # import pdb; pdb.set_trace() meas = Measurement(station=station) # qcodes measurement # self.vna.points.set(20) self.vna.auto_sweep(False) meas.register_parameter(self.vna.real) meas.register_parameter(self.vna.imaginary) meas.register_parameter(self.vna.magnitude) meas.register_parameter(self.vna.phase) # actually get the data with meas.run( ) as datasaver: # try to run the measurement (? but this doesn't yet write to the database) self.vna.active_trace.set(1) # there are Tr1 and Tr2 # self.vna.traces.tr1.run_sweep() imag = self.vna.imaginary() real = self.vna.real() mag = self.vna.magnitude() phase = self.vna.phase() datasaver.add_result( (self.vna.magnitude, mag), (self.vna.phase, phase), (self.vna.real, real), (self.vna.imaginary, imag)) dataid = datasaver.run_id pd = datasaver.dataset.get_parameter_data() snapshot = datasaver.dataset.snapshot plot_by_id(dataid)
def fill_station(param_set, param_meas): station = Station() allinstr=qc.instrument.base.Instrument._all_instruments for key,val in allinstr.items(): instr = qc.instrument.base.Instrument.find_instrument(key) station.add_component(instr) measparstring = "" for parameter in param_set: station.add_component(parameter) measparstring += parameter.name + ',' for parameter in param_meas: try: # Prevent station crash when component of parameter is not unique station.add_component(parameter) measparstring += parameter.name + ',' except Exception as e: print('Error ignored when filling station: \n', e) pass return measparstring
# -*- coding: utf-8 -*- #%% imports import inspect import numpy as np from qcodes import Station, Instrument from qcodes.utils import validators from instrumentserver import QtWidgets from instrumentserver.serialize import (saveParamsToFile, loadParamsFromFile, toParamDict, fromParamDict) from instrumentserver.gui import widgetDialog from instrumentserver.params import ParameterManager from instrumentserver.gui.instruments import ParameterManagerGui from instrumentserver.client import Client, ProxyInstrument #%% run the PM locally Instrument.close_all() pm = ParameterManager('pm') station = Station() station.add_component(pm) dialog = widgetDialog(ParameterManagerGui(pm)) #%% instantiate PM in the server. Instrument.close_all() cli = Client() pm = ProxyInstrument('pm', cli=cli, remotePath='pm') dialog = widgetDialog(ParameterManagerGui(pm))
class StationServer(QtCore.QObject): """The main server object. Encapsulated in a separate object so we can run it in a separate thread. """ # we use this to quit the server. # if this string is sent as message to the server, it'll shut down and close # the socket. Should only be used from within this module. # it's randomized in the instantiated server for a little bit of safety. SAFEWORD = 'BANANA' #: Signal(str, str) -- emit messages for display in the gui (or other stuff the gui #: wants to do with it. #: Arguments: the message received, and the reply sent. messageReceived = QtCore.Signal(str, str) #: Signal(int) -- emitted when the server is started. #: Arguments: the port. serverStarted = QtCore.Signal(str) #: Signal() -- emitted when we shut down finished = QtCore.Signal() #: Signal(Dict) -- emitted when a new instrument was created. #: Argument is the blueprint of the instrument instrumentCreated = QtCore.Signal(object) #: Signal(str, Any) -- emitted when a parameter was set #: Arguments: full parameter location as string, value parameterSet = QtCore.Signal(str, object) #: Signal(str, Any) -- emitted when a parameter was retrieved #: Arguments: full parameter location as string, value parameterGet = QtCore.Signal(str, object) #: Signal(str, List[Any], Dict[str, Any], Any) -- emitted when a function was called #: Arguments: full function location as string, arguments, kw arguments, return value funcCalled = QtCore.Signal(str, object, object, object) def __init__(self, parent=None, port=5555, allowUserShutdown=False): # , publisher_port=5554): super().__init__(parent) self.SAFEWORD = ''.join( random.choices([chr(i) for i in range(65, 91)], k=16)) self.serverRunning = False self.port = port self.station = Station() self.allowUserShutdown = allowUserShutdown # self.publisher_port = publisher_port self.parameterSet.connect( lambda n, v: logger.info(f"Parameter '{n}' set to: {str(v)}")) self.parameterGet.connect( lambda n, v: logger.debug(f"Parameter '{n}' retrieved: {str(v)}")) self.funcCalled.connect( lambda n, args, kw, ret: logger.debug(f"Function called:" f"'{n}', args: {str(args)}, " f"kwargs: {str(kw)})'.")) @QtCore.Slot() def startServer(self): """Start the server. This function does not return until the ZMQ server has been shut down.""" addr = f"tcp://*:{self.port}" logger.info(f"Starting server at {addr}") logger.info(f"The safe word is: {self.SAFEWORD}") context = zmq.Context() socket = context.socket(zmq.REP) socket.bind(addr) #creating and binding publishing socket # publisher_addr = f"tcp://*:{self.publisher_port}" # publisher_socket = context.socket(zmq.PUB) # publisher_socket.bind(publisher_addr) self.serverRunning = True self.serverStarted.emit(addr) while self.serverRunning: message = recv(socket) message_ok = True response_to_client = None response_log = None # allow the test client from within the same process to make sure the # server shuts down. This is if message == self.SAFEWORD: response_log = 'Server has received the safeword and will shut down.' response_to_client = ServerResponse(message=response_log) self.serverRunning = False logger.warning(response_log) elif self.allowUserShutdown and message == 'SHUTDOWN': response_log = 'Server shutdown requested by client.' response_to_client = ServerResponse(message=response_log) self.serverRunning = False logger.warning(response_log) # if the message is a string we just echo it back. # this is used for testing sometimes, but has no functionality. elif isinstance(message, str): response_log = f"Server has received: {message}. No further action." response_to_client = ServerResponse(message=response_log) logger.info(response_log) # we assume this is a valid instruction set now. elif isinstance(message, ServerInstruction): instruction = message try: instruction.validate() logger.info(f"Received request for operation: " f"{str(instruction.operation)}") logger.debug(f"Instruction received: " f"{str(instruction)}") except Exception as e: message_ok = False response_log = f'Received invalid message. Error raised: {str(e)}' response_to_client = ServerResponse(message=None, error=e) logger.warning(response_log) if message_ok: # we don't need to use a try-block here, because # errors are already handled in executeServerInstruction response_to_client = self.executeServerInstruction( instruction) response_log = f"Response to client: {str(response_to_client)}" if response_to_client.error is None: logger.info(f"Response sent to client.") logger.debug(response_log) else: logger.warning(response_log) else: response_log = f"Invalid message type." response_to_client = ServerResponse(message=None, error=response_log) logger.warning(f"Invalid message type: {type(message)}.") logger.debug(f"Invalid message received: {str(message)}") send(socket, response_to_client) # print("sending message") # publisher_socket.send_string("Anyone copy?") self.messageReceived.emit(str(message), response_log) # publisher_socket.close() socket.close() self.finished.emit() return True def executeServerInstruction(self, instruction: ServerInstruction) \ -> ServerResponse: """ This is the interpreter function that the server will call to translate the dictionary received from the proxy to instrument calls. :param instruction: The instruction object. :returns: the results returned from performing the operation. """ args = [] kwargs = {} # we call a helper function depending on the operation that is requested if instruction.operation == Operation.get_existing_instruments: func = self._getExistingInstruments elif instruction.operation == Operation.create_instrument: func = self._createInstrument args = [instruction.create_instrument_spec] elif instruction.operation == Operation.call: func = self._callObject args = [instruction.call_spec] elif instruction.operation == Operation.get_blueprint: func = self._getBluePrint args = [instruction.requested_path] elif instruction.operation == Operation.get_param_dict: func = self._toParamDict args = [instruction.serialization_opts] elif instruction.operation == Operation.set_params: func = self._fromParamDict args = [instruction.set_parameters] else: raise NotImplementedError try: returns = func(*args, **kwargs) response = ServerResponse(message=returns) except Exception as err: response = ServerResponse(message=None, error=err) return response def _getExistingInstruments(self) -> Dict: """ Get the existing instruments in the station, :returns : a dictionary that contains the instrument name and its class name. """ comps = self.station.components info = {k: v.__class__ for k, v in comps.items()} return info def _createInstrument(self, spec: InstrumentCreationSpec) -> None: """Create a new instrument on the server""" sep_class = spec.instrument_class.split('.') modName = '.'.join(sep_class[:-1]) clsName = sep_class[-1] mod = importlib.import_module(modName) cls = getattr(mod, clsName) args = [] if spec.args is None else spec.args kwargs = dict() if spec.kwargs is None else spec.kwargs new_instrument = qc.find_or_create_instrument(cls, name=spec.name, *args, **kwargs) if new_instrument.name not in self.station.components: self.station.add_component(new_instrument) self.instrumentCreated.emit( bluePrintFromInstrumentModule(new_instrument.name, new_instrument)) def _callObject(self, spec: CallSpec) -> Any: """call some callable found in the station.""" obj = nestedAttributeFromString(self.station, spec.target) args = spec.args if spec.args is not None else [] kwargs = spec.kwargs if spec.kwargs is not None else {} ret = obj(*args, **kwargs) if isinstance(obj, Parameter): if len(args) > 0: self.parameterSet.emit(spec.target, args[0]) else: self.parameterGet.emit(spec.target, ret) else: self.funcCalled.emit(spec.target, args, kwargs, ret) return ret def _getBluePrint( self, path: str ) -> Union[InstrumentModuleBluePrint, ParameterBluePrint, MethodBluePrint]: obj = nestedAttributeFromString(self.station, path) if isinstance(obj, tuple(INSTRUMENT_MODULE_BASE_CLASSES)): return bluePrintFromInstrumentModule(path, obj) elif isinstance(obj, tuple(PARAMETER_BASE_CLASSES)): return bluePrintFromParameter(path, obj) elif callable(obj): return bluePrintFromMethod(path, obj) else: raise ValueError(f'Cannot create a blueprint for {type(obj)}') def _toParamDict(self, opts: ParameterSerializeSpec) -> Dict[str, Any]: if opts.path is None: obj = self.station else: obj = [nestedAttributeFromString(self.station, opts.path)] includeMeta = [k for k in opts.attrs if k != 'value'] return serialize.toParamDict(obj, *opts.args, includeMeta=includeMeta, **opts.kwargs) def _fromParamDict(self, params: Dict[str, Any]): return serialize.fromParamDict(params, self.station)
class StationServer(QtCore.QObject): """The main server object. Encapsulated in a separate object so we can run it in a separate thread. Port should always be an odd number to allow the next even number to be its corresponding publishing port. """ # We use this to quit the server. # If this string is sent as message to the server, it'll shut down and close # the socket. Should only be used from within this module. # It's randomized in the instantiated server for a little bit of safety. SAFEWORD = 'BANANA' #: Signal(str, str) -- emit messages for display in the gui (or other stuff the gui #: wants to do with it. #: Arguments: the message received, and the reply sent. messageReceived = QtCore.Signal(str, str) #: Signal(int) -- emitted when the server is started. #: Arguments: the port. serverStarted = QtCore.Signal(str) #: Signal() -- emitted when we shut down. finished = QtCore.Signal() #: Signal(Dict) -- emitted when a new instrument was created. #: Argument is the blueprint of the instrument. instrumentCreated = QtCore.Signal(object) #: Signal(str, Any) -- emitted when a parameter was set #: Arguments: full parameter location as string, value. parameterSet = QtCore.Signal(str, object) #: Signal(str, Any) -- emitted when a parameter was retrieved #: Arguments: full parameter location as string, value. parameterGet = QtCore.Signal(str, object) #: Signal(str, List[Any], Dict[str, Any], Any) -- emitted when a function was called #: Arguments: full function location as string, arguments, kw arguments, return value. funcCalled = QtCore.Signal(str, object, object, object) def __init__( self, parent: Optional[QtCore.QObject] = None, port: int = 5555, allowUserShutdown: bool = False, addresses: List[str] = [], initScript: Optional[str] = None, ) -> None: super().__init__(parent) if addresses is None: addresses = [] if initScript == None: initScript = '' self.SAFEWORD = ''.join( random.choices([chr(i) for i in range(65, 91)], k=16)) self.serverRunning = False self.port = int(port) self.station = Station() self.allowUserShutdown = allowUserShutdown self.listenAddresses = list(set(['127.0.0.1'] + addresses)) self.initScript = initScript self.broadcastPort = self.port + 1 self.broadcastSocket = None self.parameterSet.connect( lambda n, v: logger.info(f"Parameter '{n}' set to: {str(v)}")) self.parameterGet.connect( lambda n, v: logger.debug(f"Parameter '{n}' retrieved: {str(v)}")) self.funcCalled.connect( lambda n, args, kw, ret: logger.debug(f"Function called:" f"'{n}', args: {str(args)}, " f"kwargs: {str(kw)})'.")) def _runInitScript(self): if os.path.exists(self.initScript): path = os.path.abspath(self.initScript) env = dict(station=self.station) exec(open(path).read(), env) else: logger.warning( f"path to initscript ({self.initScript}) not found.") @QtCore.Slot() def startServer(self) -> None: """Start the server. This function does not return until the ZMQ server has been shut down.""" logger.info(f"Starting server.") logger.info(f"The safe word is: {self.SAFEWORD}") context = zmq.Context() socket = context.socket(zmq.REP) for a in self.listenAddresses: addr = f"tcp://{a}:{self.port}" socket.bind(addr) logger.info(f"Listening at {addr}") # creating and binding publishing socket to broadcast changes broadcastAddr = f"tcp://*:{self.broadcastPort}" logger.info(f"Starting publishing server at {broadcastAddr}") self.broadcastSocket = context.socket(zmq.PUB) self.broadcastSocket.bind(broadcastAddr) self.serverRunning = True if self.initScript not in ['', None]: logger.info(f"Running init script") self._runInitScript() self.serverStarted.emit(addr) while self.serverRunning: message = recv(socket) message_ok = True response_to_client = None response_log = None # Allow the test client from within the same process to make sure the # server shuts down. This is if message == self.SAFEWORD: response_log = 'Server has received the safeword and will shut down.' response_to_client = ServerResponse(message=response_log) self.serverRunning = False logger.warning(response_log) elif self.allowUserShutdown and message == 'SHUTDOWN': response_log = 'Server shutdown requested by client.' response_to_client = ServerResponse(message=response_log) self.serverRunning = False logger.warning(response_log) # If the message is a string we just echo it back. # This is used for testing sometimes, but has no functionality. elif isinstance(message, str): response_log = f"Server has received: {message}. No further action." response_to_client = ServerResponse(message=response_log) logger.info(response_log) # We assume this is a valid instruction set now. elif isinstance(message, ServerInstruction): instruction = message try: instruction.validate() logger.info(f"Received request for operation: " f"{str(instruction.operation)}") logger.debug(f"Instruction received: " f"{str(instruction)}") except Exception as e: message_ok = False response_log = f'Received invalid message. Error raised: {str(e)}' response_to_client = ServerResponse(message=None, error=e) logger.warning(response_log) if message_ok: # We don't need to use a try-block here, because # errors are already handled in executeServerInstruction. response_to_client = self.executeServerInstruction( instruction) response_log = f"Response to client: {str(response_to_client)}" if response_to_client.error is None: logger.info(f"Response sent to client.") logger.debug(response_log) else: logger.warning(response_log) else: response_log = f"Invalid message type." response_to_client = ServerResponse(message=None, error=response_log) logger.warning(f"Invalid message type: {type(message)}.") logger.debug(f"Invalid message received: {str(message)}") send(socket, response_to_client) self.messageReceived.emit(str(message), response_log) self.broadcastSocket.close() socket.close() self.finished.emit() return True def executeServerInstruction(self, instruction: ServerInstruction) \ -> Tuple[ServerResponse, str]: """ This is the interpreter function that the server will call to translate the dictionary received from the proxy to instrument calls. :param instruction: The instruction object. :returns: The results returned from performing the operation. """ args = [] kwargs = {} # We call a helper function depending on the operation that is requested. if instruction.operation == Operation.get_existing_instruments: func = self._getExistingInstruments elif instruction.operation == Operation.create_instrument: func = self._createInstrument args = [instruction.create_instrument_spec] elif instruction.operation == Operation.call: func = self._callObject args = [instruction.call_spec] elif instruction.operation == Operation.get_blueprint: func = self._getBluePrint args = [instruction.requested_path] elif instruction.operation == Operation.get_param_dict: func = self._toParamDict args = [instruction.serialization_opts] elif instruction.operation == Operation.set_params: func = self._fromParamDict args = [instruction.set_parameters] else: raise NotImplementedError try: returns = func(*args, **kwargs) response = ServerResponse(message=returns) except Exception as err: response = ServerResponse(message=None, error=err) return response def _getExistingInstruments(self) -> Dict: """ Get the existing instruments in the station. :returns: A dictionary that contains the instrument name and its class name. """ comps = self.station.components info = {k: v.__class__ for k, v in comps.items()} return info def _createInstrument(self, spec: InstrumentCreationSpec) -> None: """Create a new instrument on the server.""" sep_class = spec.instrument_class.split('.') modName = '.'.join(sep_class[:-1]) clsName = sep_class[-1] mod = importlib.import_module(modName) cls = getattr(mod, clsName) args = [] if spec.args is None else spec.args kwargs = dict() if spec.kwargs is None else spec.kwargs new_instrument = qc.find_or_create_instrument(cls, name=spec.name, *args, **kwargs) if new_instrument.name not in self.station.components: self.station.add_component(new_instrument) self.instrumentCreated.emit( bluePrintFromInstrumentModule(new_instrument.name, new_instrument)) def _callObject(self, spec: CallSpec) -> Any: """Call some callable found in the station.""" obj = nestedAttributeFromString(self.station, spec.target) args = spec.args if spec.args is not None else [] kwargs = spec.kwargs if spec.kwargs is not None else {} ret = obj(*args, **kwargs) # Check if a new parameter is being created. self._newOrDeleteParameterDetection(spec, args, kwargs) if isinstance(obj, Parameter): if len(args) > 0: self.parameterSet.emit(spec.target, args[0]) # Broadcast changes in parameter values. self._broadcastParameterChange( ParameterBroadcastBluePrint(spec.target, 'parameter-update', args[0])) else: self.parameterGet.emit(spec.target, ret) # Broadcast calls of parameters. self._broadcastParameterChange( ParameterBroadcastBluePrint(spec.target, 'parameter-call', ret)) else: self.funcCalled.emit(spec.target, args, kwargs, ret) return ret def _getBluePrint( self, path: str ) -> Union[InstrumentModuleBluePrint, ParameterBluePrint, MethodBluePrint]: obj = nestedAttributeFromString(self.station, path) if isinstance(obj, tuple(INSTRUMENT_MODULE_BASE_CLASSES)): return bluePrintFromInstrumentModule(path, obj) elif isinstance(obj, tuple(PARAMETER_BASE_CLASSES)): return bluePrintFromParameter(path, obj) elif callable(obj): return bluePrintFromMethod(path, obj) else: raise ValueError(f'Cannot create a blueprint for {type(obj)}') def _toParamDict(self, opts: ParameterSerializeSpec) -> Dict[str, Any]: if opts.path is None: obj = self.station else: obj = [nestedAttributeFromString(self.station, opts.path)] includeMeta = [k for k in opts.attrs if k != 'value'] return serialize.toParamDict(obj, *opts.args, includeMeta=includeMeta, **opts.kwargs) def _fromParamDict(self, params: Dict[str, Any]): return serialize.fromParamDict(params, self.station) def _broadcastParameterChange(self, blueprint: ParameterBroadcastBluePrint): """ Broadcast any changes to parameters in the server. The message is composed of a 2 part array. The first item is the name of the instrument the parameter is from, with the second item being the string of the blueprint in dict format. This is done to allow subscribers to subscribe to specific instruments. :param blueprint: The parameter broadcast blueprint that is being broadcast """ self.broadcastSocket.send_string(blueprint.name.split('.')[0], flags=zmq.SNDMORE) self.broadcastSocket.send_string((blueprint.toDictFormat())) logger.info( f"Parameter {blueprint.name} has broadcast an update of type: {blueprint.action}," f" with a value: {blueprint.value}.") def _newOrDeleteParameterDetection(self, spec, args, kwargs): """ Detects if the call action is being used to create a new parameter or deletes an existing parameter. If so, it creates the parameter broadcast blueprint and broadcast it. :param spec: CallSpec object being passed to the call method. :param args: args being passed to the call method. :param kwargs: kwargs being passed to the call method. """ if spec.target.split('.')[-1] == 'add_parameter': name = spec.target.split('.')[0] + '.' + '.'.join(spec.args) pb = ParameterBroadcastBluePrint(name, 'parameter-creation', kwargs['initial_value'], kwargs['unit']) self._broadcastParameterChange(pb) elif spec.target.split('.')[-1] == 'remove_parameter': name = spec.target.split('.')[0] + '.' + '.'.join(spec.args) pb = ParameterBroadcastBluePrint(name, 'parameter-deletion') self._broadcastParameterChange(pb)
osc.ch1.t_stop.set(10) osc.ch2.t_start.set(-10) osc.ch2.t_stop.set(10) osc.ch3.t_start.set(-10) osc.ch3.t_stop.set(10) osc.ch4.t_start.set(-10) osc.ch4.t_stop.set(10) amp = 1 PSG1.amp(amp) PSG2.amp(amp) station = Station() station.snapshot() station.add_component(osc) # Criar um database initialise_or_create_database_at("~/teste.db") exp = load_or_create_experiment(experiment_name='osc realtime intro 2', sample_name="osc realtime 1") def calculateGain(): Y = osc.ch3.wavesample() n_mean = int(len(Y) / 2) value = 2 * np.mean(Y[n_mean:]) value = 10 * np.log(np.power(value, 2)) return value
self.setpoint_names = (("I_channel", ), ("Q_channel", )) self.i = 2 def get_raw(self): self.i += 1 return (self.i, self.i + 100) import qcodes from qcodes import Parameter, Station from qcodes.tests.instrument_mocks import DummyInstrument station = Station() instr = DummyInstrument('instr', gates=['input', 'output', 'gain']) instr.gain(42) # station.add_component(p) station.add_component(instr) from core_tools.data.SQL.connect import SQL_conn_info_local, SQL_conn_info_remote, sample_info, set_up_local_storage # set_up_local_storage("xld_user", "XLDspin001", "vandersypen_data", "6dot", "XLD", "6D2S - SQ21-XX-X-XX-X") # set_up_local_storage("xld_user", "XLDspin001", "vandersypen_data", "6dot", "XLD", "testing") set_up_local_storage('stephan', 'magicc', 'test', 'Intel Project', 'F006', 'SQ38328342') now = str(datetime.datetime.now()) path = os.path.join(os.getcwd(), 'test.db') initialise_or_create_database_at(path) load_or_create_experiment('tutorial ' + now, 'no sample') my_param1 = MyCounter('test_instr1') my_param2 = MyCounter('test_instr2') from qcodes.instrument.specialized_parameters import ElapsedTimeParameter
def record_S21_sweep_power_sweep_frequency(self): # -- setting vna parameters # vna.sweep_mode.set('CONT') self.vna.power.set(self.vnapower) self.vna.center.set(self.center_frequency) self.vna.span.set(self.frequency_span) self.vna.points.set(self.num_freq_points) self.vna.if_bandwidth.set(self.ifbandwidth) self.vna.trace.set(self.measuredtrace) self.vna.auto_sweep.set(False) from qcodes import Station station = Station() station.add_component(self.vna) # import pdb; pdb.set_trace() meas = Measurement(station=station) # qcodes measurement # vna.groupdelay.set(groupdelayref) #does not work yet meas = Measurement() # register the first independent parameter meas.register_parameter(self.vna.power) # register the second independent parameter meas.register_parameter(self.vna.real, setpoints=(self.vna.power, )) # ^ (? Why would vna.real be an independent parameter?) Does it not get measured (dependent) as a function of freq? meas.register_parameter( self.vna.imaginary, setpoints=(self.vna.power, )) # now register the dependent one meas.register_parameter( self.vna.phase, setpoints=(self.vna.power, )) # now register the dependent one meas.register_parameter( self.vna.magnitude, setpoints=(self.vna.power, )) # now register the dependent one # -- taking data with meas.run() as datasaver: for v1 in np.linspace(self.powersweepstart, self.powersweepstop, self.num_power_points, endpoint=True): self.vna.active_trace.set(1) power = self.vna.power.set(v1) print(self.vna.power.get()) # check # vna.auto_sweep.set(False) # vna.auto_sweep.set(True) # some bug not taking the last row therefore two sweeps self.vna.traces.tr1.run_sweep() # power=vna.power() # vna.auto_sweep.set(False) imag = self.vna.imaginary() real = self.vna.real() phase = self.vna.phase() mag = self.vna.magnitude() # vna.active_trace.set(2) # vna.traces.tr2.run_sweep() power = self.vna.power( ) # should still be the same as a few lines above # time.sleep(2) datasaver.add_result( (self.vna.magnitude, mag), (self.vna.phase, phase), (self.vna.real, real), (self.vna.imaginary, imag), (self.vna.power, power)) print(self.vna.power.get()) plot_by_id(datasaver.run_id) pd = datasaver.dataset.get_parameter_data() # import pdb; pdb.set_trace() # noqa BREAKPOINT magnitude_table = np.vstack( (np.ravel(pd[self.vna_name + "_tr1_magnitude"][self.vna_name + "_power"]), np.ravel(pd[self.vna_name + "_tr1_magnitude"][self.vna_name + "_tr1_frequency"]), np.ravel(pd[self.vna_name + "_tr1_magnitude"][self.vna_name + "_tr1_magnitude"]))) phase_table = np.vstack( (np.ravel(pd[self.vna_name + "_tr1_phase"][self.vna_name + "_power"]), np.ravel(pd[self.vna_name + "_tr1_phase"][self.vna_name + "_tr1_frequency"]), np.ravel(pd[self.vna_name + "_tr1_phase"][self.vna_name + "_tr1_phase"]))) real_table = np.vstack( (np.ravel(pd[self.vna_name + "_tr1_real"][self.vna_name + "_power"]), np.ravel(pd[self.vna_name + "_tr1_real"][self.vna_name + "_tr1_frequency"]), np.ravel(pd[self.vna_name + "_tr1_real"][self.vna_name + "_tr1_real"]))) imaginary_table = np.vstack( (np.ravel(pd[self.vna_name + "_tr1_imaginary"][self.vna_name + "_power"]), np.ravel(pd[self.vna_name + "_tr1_imaginary"][self.vna_name + "_tr1_frequency"]), np.ravel(pd[self.vna_name + "_tr1_imaginary"][self.vna_name + "_tr1_imaginary"]))) np.savetxt( os.path.join( self.raw_path_with_date, str(datasaver.run_id) + '_powersweep' + '_' + str(self.exp_name) + '_magnitude.txt'), magnitude_table) np.savetxt( os.path.join( self.raw_path_with_date, str(datasaver.run_id) + '_powersweep' + '_' + str(self.exp_name) + '_phase.txt'), phase_table) np.savetxt( os.path.join( self.raw_path_with_date, str(datasaver.run_id) + '_powersweep' + '_' + str(self.exp_name) + '_real.txt'), real_table) np.savetxt( os.path.join( self.raw_path_with_date, str(datasaver.run_id) + '_powersweep' + '_' + str(self.exp_name) + '_imaginary.txt'), imaginary_table)
class UImain(QtWidgets.QMainWindow): def __init__(self, parent=None, config_file=None): super(UImain, self).__init__(parent) self.ui = Ui_MeasureIt() self.ui.setupUi(self) self.setWindowTitle("MeasureIt") self.ui.scanValue.setText('False') self.ui.scanValue.setStyleSheet('color: red') self.ui.scanParameterBox.addItem('time', 'time') self.sweep_settings = { 'time': { 'start': '', 'end': '', 'step': '', 'step_sec': '', 'continual': False, 'bidirectional': False, 'plot_bin': 1, 'save_data': True, 'plot_data': True, 'ramp_to_start': True } } self.set_param_index = 0 self.init_tables() self.make_connections() self.station = None self.sweep = None self.sweep_queue = SweepQueue(inter_delay=3) self.devices = {} self.track_params = {} self.set_params = {} self.shown_follow_params = [] self.shown_set_params = [] self.device_init = {} self.db = '' self.exp_name = '' self.sample_name = '' self.db_set = False self.datasets = [] self.update_instrument_menu() self.load_station_and_connect_instruments(config_file) self.update_datasets() self.start_logs() # Create Queue and redirect sys.stdout to this queue queue = Queue() sys.stdout = WriteStream(queue) self.thread = OutputThread(queue) self.thread.mysignal.connect(self.append_stdout) self.thread.start() self.show() def init_tables(self): follow_header = self.ui.followParamTable.horizontalHeader() follow_header.setSectionResizeMode(0, QHeaderView.ResizeToContents) follow_header.resizeSection(0, 60) follow_header.setSectionResizeMode(1, QHeaderView.Fixed) follow_header.resizeSection(1, 60) follow_header.setSectionResizeMode(2, QHeaderView.Stretch) follow_header.setSectionResizeMode(3, QHeaderView.ResizeToContents) follow_header.setSectionResizeMode(4, QHeaderView.Fixed) follow_header.resizeSection(4, 40) output_header = self.ui.outputParamTable.horizontalHeader() output_header.setSectionResizeMode(0, QHeaderView.ResizeToContents) output_header.resizeSection(0, 60) output_header.setSectionResizeMode(1, QHeaderView.Fixed) output_header.resizeSection(1, 60) output_header.setSectionResizeMode(2, QHeaderView.Stretch) output_header.setSectionResizeMode(3, QHeaderView.Fixed) output_header.resizeSection(3, 40) output_header.setSectionResizeMode(4, QHeaderView.Fixed) output_header.resizeSection(4, 40) def make_connections(self): self.ui.editParameterButton.clicked.connect(self.edit_parameters) self.ui.startButton.clicked.connect(self.start_sweep) self.ui.pauseButton.clicked.connect(self.pause_resume_sweep) self.ui.flipDirectionButton.clicked.connect(self.flip_direction) self.ui.endButton.clicked.connect(self.end_sweep) self.ui.saveButton.clicked.connect(self.setup_save) self.ui.addSweepButton.clicked.connect(self.add_sweep_to_queue) self.ui.removeActionButton.clicked.connect( lambda: self.remove_action_from_queue(self.ui.sequenceWidget. currentRow())) self.ui.startSequenceButton.clicked.connect(self.start_sequence) self.ui.addSaveButton.clicked.connect(self.add_save_to_sequence) self.ui.upSequenceButton.clicked.connect( lambda: self.move_action_in_sequence(-1)) self.ui.downSequenceButton.clicked.connect( lambda: self.move_action_in_sequence(+1)) self.ui.actionSaveStation.triggered.connect(self.save_station) self.ui.actionLoadStation.triggered.connect(self.load_station) self.ui.actionQuit.triggered.connect(self.close) self.ui.actionLoad_Sweep.triggered.connect(self.load_sweep) self.ui.actionSave_Sweep.triggered.connect(self.save_sweep) self.ui.actionSave_Sequence.triggered.connect(self.save_sequence) self.ui.actionLoad_Sequence.triggered.connect(self.load_sequence) self.ui.sequenceWidget.itemDoubleClicked.connect( self.edit_sequence_item) self.ui.scanParameterBox.currentIndexChanged.connect( self.update_param_combobox) self.update_param_combobox(0) def update_param_combobox(self, index): old_set_param = self.ui.scanParameterBox.itemData(self.set_param_index) self.sweep_settings[old_set_param] = { 'start': self.ui.startEdit.text(), 'end': self.ui.endEdit.text(), 'step': self.ui.stepEdit.text(), 'step_sec': self.ui.stepsecEdit.text(), 'save_data': self.ui.saveBox.isChecked(), 'plot_data': self.ui.livePlotBox.isChecked(), 'plot_bin': self.ui.plotbinEdit.text(), 'bidirectional': self.ui.bidirectionalBox.isChecked(), 'continual': self.ui.continualBox.isChecked() } if index == 0: self.ui.startEdit.setReadOnly(True) p = self.ui.startEdit.palette() p.setColor(self.ui.startEdit.backgroundRole(), Qt.gray) self.ui.startEdit.setPalette(p) self.ui.stepEdit.setReadOnly(True) q = self.ui.stepEdit.palette() q.setColor(self.ui.stepEdit.backgroundRole(), Qt.gray) self.ui.stepEdit.setPalette(q) else: self.ui.startEdit.setReadOnly(False) p = self.ui.startEdit.palette() p.setColor(self.ui.startEdit.backgroundRole(), Qt.white) self.ui.startEdit.setPalette(p) self.ui.stepEdit.setReadOnly(False) q = self.ui.stepEdit.palette() q.setColor(self.ui.stepEdit.backgroundRole(), Qt.white) self.ui.stepEdit.setPalette(q) self.update_sweep_box( self.sweep_settings[self.ui.scanParameterBox.currentData()]) self.set_param_index = index def start_logs(self): self.stdout_filename = os.environ[ 'MeasureItHome'] + '\\logs\\stdout\\' + datetime.now().strftime( "%Y-%m-%d") + '.txt' self.stderr_filename = os.environ[ 'MeasureItHome'] + '\\logs\\stderr\\' + datetime.now().strftime( "%Y-%m-%d") + '.txt' self.stdout_file = open(self.stdout_filename, 'a') sys.stderr = open(self.stderr_filename, 'a') self.stdout_file.write('Started program at ' + datetime.now().strftime("%H:%M:%S") + '\n') print('Started program at ' + datetime.now().strftime("%H:%M:%S"), file=sys.stderr) self.stdout_file.close() start_all_logging() def load_station(self): (fileName, x) = QFileDialog.getOpenFileName( self, "Load Station", os.environ['MeasureItHome'] + "\\cfg\\", "Stations (*.station.yaml)") if len(fileName) == 0: return for name in list(self.devices.keys()): self.do_remove_device(name) self.load_station_and_connect_instruments(fileName) def load_station_and_connect_instruments(self, config_file=None): self.station = Station() try: self.station.load_config_file(config_file) except Exception as e: self.show_error( "Error", "Couldn't open the station configuration file. Started new station.", e) return if self.station.config is None: return for name, instr in self.station.config['instruments'].items(): try: dev = self.station.load_instrument(name) self.devices[str(name)] = dev except Exception as e: self.show_error( 'Instrument Error', f'Error connecting to {name}, ' 'either the name is already in use or the device is unavailable.', e) self.update_instrument_menu() def save_station(self): ss_ui = SaveStationGUI(self) if ss_ui.exec_(): fp = ss_ui.get_file() default = ss_ui.ui.defaultBox.isChecked() if len(fp) > 0: self.do_save_station(fp, default) def do_save_station(self, filename, set_as_default=False): def add_field(ss, instr, field, value): try: ss[field] = instr[value] except KeyError: pass if '.station.yaml' not in filename: filename += '.station.yaml' snap = {'instruments': {}} for name, instr in self.station.snapshot()['instruments'].items(): snap['instruments'][name] = {} add_field(snap['instruments'][name], instr, 'type', '__class__') add_field(snap['instruments'][name], instr, 'address', 'address') snap['instruments'][name]['enable_forced_reconnect'] = True if name in self.device_init: snap['instruments'][name]['init'] = {} for key, value in self.device_init[name].items(): snap['instruments'][name]['init'][key] = value # Could also save parameter information here with open(filename, 'w') as file: yaml = YAML() yaml.dump(snap, file) if set_as_default: qc.config['station']['default_file'] = filename qc.config.save_config(os.environ['MeasureItHome'] + '\\cfg\\qcodesrc.json') def edit_parameters(self): param_ui = EditParameterGUI(self.devices, self.track_params, self.set_params, self) if param_ui.exec_(): self.track_params = param_ui.new_track_params self.set_params = param_ui.new_set_params print('Here are the parameters currently being tracked:') for name, p in self.track_params.items(): print(name) print('Here are the parameters available for sweeping:') for name, p in self.set_params.items(): print(name) self.update_parameters() def update_parameters(self): # Set up the follow parameter table self.ui.followParamTable.clearContents() self.ui.followParamTable.setRowCount(0) for m, (name, p) in enumerate(self.track_params.items()): self.ui.followParamTable.insertRow(m) paramitem = QTableWidgetItem(name) paramitem.setData(32, p) paramitem.setFlags(Qt.ItemIsSelectable) self.ui.followParamTable.setItem(m, 0, paramitem) labelitem = QLineEdit(p.label) labelitem.editingFinished.connect( lambda p=p, labelitem=labelitem: self.update_labels( p, labelitem.text())) self.ui.followParamTable.setCellWidget(m, 1, labelitem) valueitem = QTableWidgetItem(str(self.get_param(p))) self.ui.followParamTable.setItem(m, 2, valueitem) includeBox = QCheckBox() includeBox.setChecked(True) self.ui.followParamTable.setCellWidget(m, 3, includeBox) updateButton = QPushButton("Get") updateButton.clicked.connect( lambda checked, m=m, p=p, valueitem=valueitem: valueitem. setText(str(self.get_param(p)))) self.ui.followParamTable.setCellWidget(m, 4, updateButton) # Set up the output parameter table self.ui.outputParamTable.clearContents() self.ui.outputParamTable.setRowCount(0) self.ui.scanParameterBox.clear() self.ui.scanParameterBox.addItem('time', 'time') for n, (name, p) in enumerate(self.set_params.items()): self.ui.outputParamTable.insertRow(n) paramitem = QTableWidgetItem(name) paramitem.setData(32, p) paramitem.setFlags(Qt.ItemIsSelectable) self.ui.outputParamTable.setItem(n, 0, paramitem) labelitem = QLineEdit(p.label) labelitem.editingFinished.connect( lambda p=p, labelitem=labelitem: self.update_labels( p, labelitem.text())) self.ui.outputParamTable.setCellWidget(n, 1, labelitem) valueitem = QLineEdit(str(self.get_param(p))) self.ui.outputParamTable.setCellWidget(n, 2, valueitem) setButton = QPushButton("Set") setButton.clicked.connect(lambda checked, p=p, valueitem=valueitem: self.set_param(p, valueitem)) self.ui.outputParamTable.setCellWidget(n, 3, setButton) getButton = QPushButton("Get") getButton.clicked.connect( lambda checked, p=p, valueitem=valueitem: valueitem.setText( str(self.get_param(p)))) self.ui.outputParamTable.setCellWidget(n, 4, getButton) self.ui.scanParameterBox.addItem(p.label, p) if p not in list(self.sweep_settings.keys()): self.sweep_settings[p] = { 'start': '', 'end': '', 'step': '', 'step_sec': '', 'continual': False, 'bidirectional': False, 'plot_bin': 1, 'save_data': True, 'plot_data': True, 'ramp_to_start': True } def set_param(self, p, valueitem): try: if "Int" in repr(p.vals) or "Number" in repr(p.vals): safe_set(p, _value_parser(valueitem.text())) elif "String" in repr(p.vals): safe_set(p, str(valueitem.text())) elif "Bool" in repr(p.vals) or 'False' in repr(p.vals): value = valueitem.text() if value == "false" or value == "False" or value == "0": safe_set(p, False) elif value == "true" or value == "True" or value == "1": safe_set(p, True) else: safe_set(p, value) else: safe_set(p, valueitem.text()) except ParameterException: self.show_error( 'Error', f'Could not set {p.label} to {valueitem.text()}. Check the command and try ' 'again.') def get_param(self, p): try: return str(safe_get(p)) except ParameterException as e: self.show_error( 'Error', f'Could not get {p.label}. Check the exception and try again.', e) return '' def update_labels(self, p, newlabel): p.label = newlabel for n, (name, param) in enumerate(list(self.track_params.items())): self.ui.followParamTable.cellWidget(n, 1).setText(param.label) for n, (name, param) in enumerate(list(self.set_params.items())): self.ui.outputParamTable.cellWidget(n, 1).setText(param.label) for n in range(self.ui.scanParameterBox.count() - 1): param = self.ui.scanParameterBox.itemData(n + 1) self.ui.scanParameterBox.setItemText(n + 1, param.label) def create_sweep(self): # Check if we're scanning time, then if so, do Sweep0D if self.ui.scanParameterBox.currentText() == 'time': stop = _value_parser(self.ui.endEdit.text()) stepsec = _value_parser(self.ui.stepsecEdit.text()) plotbin = self.ui.plotbinEdit.text() plotbin = int(plotbin) if plotbin < 1: self.ui.plotbinEdit.setText('1') raise ValueError save = self.ui.saveBox.isChecked() plot = self.ui.livePlotBox.isChecked() sweep = Sweep0D(max_time=stop, inter_delay=1 / stepsec, save_data=save, plot_data=plot, plot_bin=plotbin) # Set up Sweep1D if we're not sweeping time else: start = _value_parser(self.ui.startEdit.text()) stop = _value_parser(self.ui.endEdit.text()) step = _value_parser(self.ui.stepEdit.text()) stepsec = _value_parser(self.ui.stepsecEdit.text()) plotbin = self.ui.plotbinEdit.text() plotbin = int(plotbin) if plotbin < 1: self.ui.plotbinEdit.setText('1') raise ValueError set_param = self.ui.scanParameterBox.currentData() twoway = self.ui.bidirectionalBox.isChecked() continuous = self.ui.continualBox.isChecked() save = self.ui.saveBox.isChecked() plot = self.ui.livePlotBox.isChecked() sweep = Sweep1D(set_param, start, stop, step, inter_delay=1.0 / stepsec, bidirectional=twoway, continual=continuous, save_data=save, plot_data=plot, x_axis_time=0, plot_bin=plotbin) for n in range(self.ui.followParamTable.rowCount()): if self.ui.followParamTable.cellWidget(n, 3).isChecked(): param = self.ui.followParamTable.item(n, 0).data(32) if param is not sweep.set_param: sweep.follow_param(param) sweep.update_signal.connect(self.receive_updates) sweep.dataset_signal.connect(self.receive_dataset) if isinstance(sweep, Sweep0D) and len( sweep._params) == 0 and sweep.plot_data: self.show_error( "Error", "Can't plot time against nothing. Either select some parameters to follow or " "unselect \'plot data\'.") sweep = None return sweep def start_sweep(self): if self.sweep is not None: if self.sweep.is_running: alert = QMessageBox() new_sweep = alert.question( self, "Warning!", "A sweep is already running! Stop the current sweep and start a new one?", alert.Yes | alert.No) if new_sweep == alert.Yes: self.sweep.stop() self.sweep.kill() self.sweep = None else: return elif self.sweep.set_param == self.ui.scanParameterBox.currentData() \ and self.ui.rampToStartBox.isChecked() is False: alert = QMessageBox() new_sweep = alert.question( self, "Warning!", "You are about to start a new sweep of the parameter you just swept, " "without ramping from the current setpoint to the start value. Are you " "sure you wish to do so?", alert.Yes | alert.No) if new_sweep == alert.Yes: self.sweep.kill() self.sweep = None else: return else: self.sweep.kill() try: self.sweep = self.create_sweep() if self.sweep is None: return except ValueError: self.show_error( "Error", "One or more of the sweep input values are invalid. " "Valid inputs consist of a number optionally followed by " "suffix f/p/n/u/m/k/M/G.") return save = self.ui.saveBox.isChecked() if save and self.db_set is False: if not self.setup_save(): self.show_error( 'Error', "Database was not opened. Set save information before running the sweep again." ) return self.sweep.start(ramp_to_start=self.ui.rampToStartBox.isChecked()) def pause_resume_sweep(self): if self.sweep is None: return if self.sweep.is_running: self.sweep.stop() self.ui.pauseButton.setText("Resume") else: self.sweep.resume() self.ui.pauseButton.setText("Pause") def flip_direction(self): if self.sweep is None: return self.sweep.flip_direction() def end_sweep(self): if self.sweep is None: return print('trying to kill the sweep') self.sweep.kill() self.sweep = None def add_sweep_to_queue(self): try: sweep = self.create_sweep() if sweep is None: return except ValueError as e: self.show_error( "Error", "One or more of the sweep input values are invalid. " "Valid inputs consist of a number optionally followed by " "suffix f/p/n/u/m/k/M/G.", e) return self.sweep_queue.append(sweep) self.update_sequence_table() def update_sequence_table(self, cursor=-1): self.ui.sequenceWidget.clear() for n, action in enumerate(self.sweep_queue.queue): item = QListWidgetItem(action.__repr__()) item.setData(32, action) self.ui.sequenceWidget.addItem(item) self.ui.sequenceWidget.setCurrentRow(cursor) def remove_action_from_queue(self, action): if isinstance(action, int) and action >= 0: self.sweep_queue.delete(action) self.update_sequence_table() def move_action_in_sequence(self, change): row = self.ui.sequenceWidget.currentRow() if row == -1: return action = self.ui.sequenceWidget.currentItem().data(32) new_pos = self.sweep_queue.move(action, change) self.update_sequence_table(cursor=new_pos) def add_save_to_sequence(self): default_db = self.db default_exp = self.exp_name default_sample = self.sample_name for action in self.sweep_queue.queue: if isinstance(action, DatabaseEntry): default_db = action.db default_exp = action.exp default_sample = action.samp save_data_ui = SaveDataGUI(self, default_db, default_exp, default_sample) if save_data_ui.exec_(): (db, exp_name, sample_name) = save_data_ui.get_save_info() db_entry = DatabaseEntry(db, exp_name, sample_name, self.sweep_queue.begin_next) self.sweep_queue.append(db_entry) self.update_sequence_table() def edit_sequence_item(self, action): n = -1 for num, item in enumerate(self.sweep_queue.queue): if action.data(32) is item: n = num if n == -1: return if isinstance(self.sweep_queue.queue[n], BaseSweep): edit_sweep_ui = EditSweepGUI(self, self.sweep_queue.queue[n]) r = edit_sweep_ui.exec_() if r == 1: self.sweep_queue.replace(n, edit_sweep_ui.return_sweep()) self.update_sequence_table() elif r == 2: self.sweep_queue.delete(n) self.update_sequence_table() elif isinstance(self.sweep_queue.queue[n], DatabaseEntry): entry = self.sweep_queue.queue[n] save_data_ui = SaveDataGUI(self, entry.db, entry.exp, entry.samp) if save_data_ui.exec_(): (db, exp_name, sample_name) = save_data_ui.get_save_info() db_entry = DatabaseEntry(db, exp_name, sample_name, self.sweep_queue.begin_next) self.sweep_queue.replace(n, db_entry) self.update_sequence_table() def start_sequence(self): if self.sweep is not None: if self.sweep.is_running: alert = QMessageBox() new_sweep = alert.question( self, "Warning!", "A sweep is already running! Stop the current sweep and start a new one?", alert.Yes | alert.No) if new_sweep == alert.Yes: self.sweep.stop() self.sweep.kill() self.sweep = None else: return else: self.sweep.kill() save_configured = False for s in self.sweep_queue.queue: if isinstance(s, DatabaseEntry): save_configured = True elif isinstance(s, BaseSweep): if s.save_data is True and save_configured is False: self.show_error( 'Error', 'A sweep will try to save data before a database location is set. Fix ' 'and try again.') return self.sweep_queue.newSweepSignal.connect( lambda sweep: self.new_queue_sweep(sweep)) self.sweep_queue.start() def new_queue_sweep(self, sweep): self.sweep = sweep self.update_sequence_table() def setup_save(self): save_data_ui = SaveDataGUI(self, self.db, self.exp_name, self.sample_name) if save_data_ui.exec_(): (self.db, self.exp_name, self.sample_name) = save_data_ui.get_save_info() try: initialise_or_create_database_at(self.db) qc.new_experiment(self.exp_name, self.sample_name) self.db_set = True return True except Exception as e: self.show_error('Error', "Error opening up database. Try again.", e) return False else: return False def save_sweep(self): if self.sweep is None: self.sweep = self.create_sweep() (filename, x) = QFileDialog.getSaveFileName( self, "Save Sweep as JSON", f"{os.environ['MeasureItHome']}\\Experiments\\untitled_sweep.json", "JSON (*.txt *.json)") if len(filename) > 0: self.sweep.export_json(filename) def load_sweep(self): (filename, x) = QFileDialog.getOpenFileName( self, "Load Sweep from JSON", f"{os.environ['MeasureItHome']}\\Experiments\\", "JSON (*.txt *.json)") if len(filename) > 0: try: new_sweep = BaseSweep.init_from_json(filename, self.station) self.sweep = new_sweep settings = { 'start': self.sweep.begin, 'end': self.sweep.end, 'step': self.sweep.step, 'step_sec': 1 / self.sweep.inter_delay, 'save_data': self.sweep.save_data, 'plot_data': self.sweep.plot_data, 'plot_bin': self.sweep.plot_bin, 'bidirectional': self.sweep.bidirectional, 'continual': self.sweep.continuous } self.update_sweep_box(settings) # Load parameters # TODO: set the set_param box except Exception as e: self.show_error('Error', "Could not load the sweep.", e) def update_sweep_box(self, settings): self.ui.startEdit.setText(str(settings['start'])) self.ui.endEdit.setText(str(settings['end'])) self.ui.stepEdit.setText(str(settings['step'])) self.ui.stepsecEdit.setText(str(settings['step_sec'])) self.ui.saveBox.setChecked(settings['save_data']) self.ui.livePlotBox.setChecked(settings['plot_data']) self.ui.plotbinEdit.setText(str(settings['plot_bin'])) self.ui.bidirectionalBox.setChecked(settings['bidirectional']) self.ui.continualBox.setChecked(settings['continual']) def save_sequence(self): (filename, x) = QFileDialog.getSaveFileName( self, "Save Sequence as JSON", f"{os.environ['MeasureItHome']}\\Experiments\\untitled.json", "JSON (*.txt *.json)") if len(filename) > 0: self.sweep_queue.export_json(filename) def load_sequence(self): (filename, x) = QFileDialog.getOpenFileName( self, "Load Sequence from JSON", f"{os.environ['MeasureItHome']}\\Experiments\\", "JSON (*.txt *.json)") if len(filename) > 0: try: new_queue = SweepQueue.init_from_json(filename, self.station) self.sweep_queue = new_queue self.update_sequence_table() for sweep in self.sweep_queue.queue: sweep.dataset_signal.connect(self.receive_dataset) sweep.update_signal.connect(self.receive_updates) except Exception as e: self.show_error('Error', "Could not load the sequence.", e) def add_device(self): # TODO: # Add in ability to pass args and kwargs to the constructor instrument_ui = AddInstrumentGUI(self) if instrument_ui.exec_(): d = instrument_ui.get_selected() try: d['name'] = _name_parser(d['name']) except ValueError as e: self.show_error("Error", "Instrument name must start with a letter.", e) return if instrument_ui.ui.nameEdit.text() in self.devices.keys(): self.show_error( "Error", "Already have an instrument with that name in the station." ) return # Now, set up our initialization for each device, if it doesn't follow the standard initialization new_dev = self.connect_device(d['device'], d['class'], d['name'], d['address'], d['args'], d['kwargs']) if new_dev is not None: self.devices[d['name']] = new_dev self.station.add_component(new_dev, update_snapshot=False) self.update_instrument_menu() def connect_device(self, device, classtype, name, address, args=[], kwargs={}): new_dev = None if name in Instrument.instances(): self.show_error( "Error", f'Instrument name is already in use. Try again with a new name.' ) return None try: if device == 'Dummy' or device == 'Test': new_dev = classtype(name) else: new_dev = classtype(name, address, *args, **kwargs) if len(kwargs.keys()) > 0: self.device_init[name] = kwargs except Exception as e: self.show_error( "Error", f'Couldn\'t connect to the instrument. Check address and try again.', e) print(e, file=sys.stderr) if hasattr(new_dev, 'close'): new_dev.close() new_dev = None return new_dev def update_instrument_menu(self): # TODO: # Add some clickable action to the name hanging out in the device menu self.ui.menuInstruments.clear() self.ui.addInstrumentAction = QAction("Add instrument...", self.ui.menuInstruments) self.ui.addInstrumentAction.setStatusTip("Connect to a new instrument") self.ui.addInstrumentAction.triggered.connect(self.add_device) self.ui.removeInstrumentAction = QAction("Remove instrument...", self.ui.menuInstruments) self.ui.removeInstrumentAction.setStatusTip("Disconnect an instrument") self.ui.removeInstrumentAction.triggered.connect(self.remove_device) self.ui.menuInstruments.addAction(self.ui.addInstrumentAction) self.ui.menuInstruments.addAction(self.ui.removeInstrumentAction) self.ui.menuInstruments.addSeparator() for name, dev in self.devices.items(): act = self.ui.menuInstruments.addAction( f"{dev.name} ({dev.__class__.__name__})") act.setData(dev) def remove_device(self): remove_ui = RemoveInstrumentGUI(self.devices, self) if remove_ui.exec_(): dev = remove_ui.ui.instrumentBox.currentText() if len(dev) > 0: self.do_remove_device(dev) def do_remove_device(self, name): self.station.remove_component(name) dev = self.devices.pop(name) dev.close() if name in self.device_init.keys(): self.device_init.pop(name) self.update_instrument_menu() @pyqtSlot(str) def append_stdout(self, text): self.ui.consoleEdit.moveCursor(QTextCursor.End) self.ui.consoleEdit.insertPlainText(text) self.stdout_file = open(self.stdout_filename, 'a') time = datetime.now().strftime("%H:%M:%S") self.stdout_file.write(time + '\t' + text) self.stdout_file.close() @pyqtSlot(dict) def receive_updates(self, update_dict): is_running = update_dict['status'] set_param = update_dict['set_param'] setpoint = update_dict['setpoint'] direction = update_dict['direction'] self.ui.scanValue.setText(f'{is_running}') if is_running: self.ui.scanValue.setStyleSheet('color: green') self.ui.pauseButton.setText('Pause') else: self.ui.scanValue.setStyleSheet('color: red') self.ui.pauseButton.setText('Resume') if set_param == 'time': self.ui.paramValue.setText('time') else: self.ui.paramValue.setText(f'{set_param.label}') if setpoint is not None: self.ui.setpointValue.setText(f'{str(setpoint)}') if direction: self.ui.directionValue.setText('Backward') else: self.ui.directionValue.setText('Forward') @pyqtSlot(dict) def receive_dataset(self, dataset): self.datasets.append(dataset) self.update_datasets() def update_datasets(self): self.ui.menuData.clear() self.ui.loadDatabaseAction = QAction("Load Database", self) self.ui.loadDatabaseAction.setStatusTip("Load runs from database") self.ui.loadDatabaseAction.triggered.connect(self.load_database) self.ui.exportDatasetAction = QAction("Export All", self) self.ui.exportDatasetAction.setStatusTip( "Export all datasets currently loaded to csv") self.ui.exportDatasetAction.triggered.connect(self.export_all_datasets) self.ui.removeDatasetAction = QAction("Remove All", self) self.ui.removeDatasetAction.setStatusTip( "Remove all datasets currently loaded (does not delete data") self.ui.removeDatasetAction.triggered.connect(self.remove_all_datasets) self.ui.menuData.addAction(self.ui.loadDatabaseAction) self.ui.menuData.addAction(self.ui.exportDatasetAction) self.ui.menuData.addAction(self.ui.removeDatasetAction) self.ui.menuData.addSeparator() for ds in self.datasets: act = self.ui.menuData.addAction( f"{ds['run id']} - {ds['exp name']} / {ds['sample name']}") act.setData(ds) act.triggered.connect(partial(self.view_dataset, ds)) def load_database(self): def check_existing_ds(ds): for old_ds in self.datasets: if str(ds['run id']) == str(old_ds['run id']) and str(ds['exp name']) == str(old_ds['exp name']) \ and str(ds['sample name']) == str(old_ds['sample name']) and str(ds['db']) == str(old_ds['db']): return False return True gui = SaveDataGUI(self) if gui.exec_(): (db, exp_name, sample_name) = gui.get_save_info() initialise_or_create_database_at(db) exps = experiments() new_datasets = 0 for exp in exps: for ds in exp.data_sets(): if len(exp_name) == 0 or ds.exp_name == exp_name: if len(sample_name ) == 0 or ds.sample_name == sample_name: new_ds = {} new_ds['run id'] = ds.run_id new_ds['exp name'] = ds.exp_name new_ds['sample name'] = ds.sample_name new_ds['db'] = ds.path_to_db if check_existing_ds(new_ds) is True: self.datasets.append(new_ds) new_datasets += 1 self.update_datasets() if new_datasets == 0: self.show_error( 'Error', 'No (new) data sets found with the specified experiment and sample name!' ) def view_dataset(self, ds): dataset_gui = ViewDatasetGUI(self, ds) dataset_gui.show() dataset_gui.activateWindow() def export_all_datasets(self): directory = QFileDialog.getExistingDirectory( self, "Save Data to .csv", f'{os.environ["MeasureItHome"]}\\Origin Files\\') if len(directory) == 0: return unsaved_sets = [] for ds_info in self.datasets: try: ds = load_by_run_spec(experiment_name=ds_info['exp name'], sample_name=ds_info['sample name'], captured_run_id=ds_info['run id']) filename = f"{directory}\\{ds.run_id}_{ds.exp_name}_{ds.sample_name}.csv" save_to_csv(ds, filename) except: unsaved_sets.append( f"{ds.run_id}_{ds.exp_name}_{ds.sample_name}") if len(unsaved_sets) > 0: error_text = 'Failed to export the following datasets:\n\n' for i, ds in enumerate(unsaved_sets): error_text += ds if i + 1 != len(unsaved_sets): error_text += ', ' error_text += '.\n\nThis is possibly due to a file name conflict or due to no data being stored in that run.' self.show_error('Error', error_text) def remove_all_datasets(self): alert = QMessageBox() removal = alert.question( self, "Warning!", "You are about to remove all the currently loaded datasets. This will not delete " "the data, but you will have to reload each run to access them again here. Are you " "sure you want to do so?", alert.Yes | alert.No) if removal == alert.Yes: self.datasets = [] self.update_datasets() def show_error(self, title, message, e=None): msg_box = QMessageBox() msg_box.setWindowTitle(title) if e is not None: message += f'\n\nPython message: {e}' msg_box.setText(message) msg_box.setStandardButtons(QMessageBox.Ok) msg_box.exec_() def exit(self): for key, dev in self.devices.items(): dev.close() if self.sweep is not None: self.sweep.kill() self.thread.stop = True self.thread.exit() if not self.thread.wait(5000): self.thread.terminate() print("Forced stdout thread to terminate.", file=sys.stderr) self.stdout_file = open(self.stdout_filename, 'a') self.stdout_file.write("Program exited at " + datetime.now().strftime("%H:%M:%S") + '\n') print("Program exited at " + datetime.now().strftime("%H:%M:%S"), file=sys.stderr) self.stdout_file.close() app = QtGui.QGuiApplication.instance() app.closeAllWindows() def closeEvent(self, event): are_you_sure = QMessageBox() close = are_you_sure.question( self, "Exit", "Are you sure you want to close all windows and exit the application?", are_you_sure.Yes | are_you_sure.No) if close == are_you_sure.Yes: self.exit() event.accept() else: event.ignore() return