Welcome to CustomXepr’s documentation

This documentation provides both a tutorial-like introduction to CustomXepr and a detailed reference of the API (currently only non-GUI classes):

Documentation Status

Warning: Version 2.3.3 is the last release that supports Python 2.7. All newer releases only support Python 3.6 and higher.

CustomXepr

A Python instrument controller and GUI for Bruker E500 EPR spectrometers, MercuryiTC temperature controllers and Keithley 2600 series source measurement units. CustomXepr relies on the python drivers keithley2600 and mercuryitc and the respective user interfaces keithleygui and mercurygui for functionality regarding the Keithley 2600 and MercuryiTC instruments.

Screenshot of CustomXepr GUI

Overview

CustomXepr for Linux and macOS enables the interaction with all instruments involved in field induced electron spin resonance (FI-EPR) measurements: the Bruker E500 spectrometer, through Bruker’s Xepr Python API, the Oxford Instruments MercuryiTC temperature controller, and the Keithley 2600 series of source measurement units (SMUs). The program suite is structured into drivers and user interfaces for individual instruments (external packages), CustomXepr’s main class which provides higher level functions that often combine functionality from multiple instruments, and a manager which handles the scheduling of experiments.

The aim of CustomXepr is twofold: First and foremost, it enables the user to automate and schedule full measurement plans which may run for weeks without user input. Second, it complements the functionality of Bruker’s Xepr control software. This includes for instance powerful logging capabilities, a more accurate determination of the cavity’s Q-value from its frequency response, more reliable tuning of the cavity, the ability to re-tune the cavity during long-running measurements, logging of the cryostat temperature during measurements, and many more. Low level functionality and communication with the spectrometer remains with Xepr.

CustomXepr structure

Finally, CustomXepr fully supports Bruker BES3T data files (DSC, DTA, etc). The customxepr.experiment.XeprData class enables loading, plotting, modifying and saving such data files from regular, 2D or pulsed experiements. It also supports reading and plotting the pulse sequences used to acquire the data, as saved in the DSC file. More information is provided in the API documentation for the XeprData class.

Installation

Make sure that you have PyQt or PySide installed on your system (all other dependencies will be installed automatically). Then install CustomXepr by running in a terminal:

$ pip install git+https://github.com/OE-FET/customxepr

Instrument communication

CustomXepr communicates with with the Keithley and MercuryiTC through NI-VISA or pyvisa-py and is therefore independent of the actual interface, e.g., Ethernet, USB, or GPIB. Connections to the EPR spectrometer are handled through Bruker’s Xepr Python API.

Usage

CustomXepr can be run interactively from a Jupyter console, or as a standalone program. In the latter case, it will create its own internal Jupyter console for the user to run commands.

You can start CustomXepr from a Python command prompt as follows:

>>> from customxepr import run_gui
>>> run_gui()

To start the CustomXepr GUI from a console / terminal, run customxepr.

CustomXepr has a user interface which displays all jobs waiting in the queue, all results returned from previous jobs, and all logging messages. Common tasks such as pausing, aborting and clearing jobs, plotting and saving returned data, and setting temperature stability tolerances can be performed through the interface itself. However, apart from tuning the cavity and reading a Q-factor, all jobs must be scheduled programmatically through the provided Jupyter console.

Job-scheduling

CustomXepr’s core consists of functions for preconfigured tasks, such as changing the cryostat temperature, recording a transfer curve, performing a preconfigured EPR measurement. For instance, customXepr.setTemperature(110) tells the MercuryiTC to change its temperature set-point to 110 K and waits until the latter is reached and maintained with the desired stability (default: ±0.1 K for 120 sec). It also adjusts the helium flow if necessary and warns the user if the target temperature cannot be reached within the expected time. customXepr.runExperiment(powersat) will run the preconfigured EPR measurement “powersat” while tuning the cavity between scans and monitoring the temperature stability during the measurement.

Such built in jobs are not performed immediately but are queued and run after the successful completion of the previous jobs. Any data returned by a job, such as a transfer curve or a cavity mode picture, will be kept in a result queue and saved to a specified file if requested. If the returned object has save and plot methods implemented, one can right-click on its entry in the GUI to plot the data or save it to the hard drive.

CustomXepr functions that are expected to run for longer than 1 sec can gracefully abort upon user request without leaving the setup in an inconsistent state.

Screenshot of CustomXepr GUI

In addition, the queuing system can be used to manually schedule any user-specified jobs, related or unrelated to the EPR setup and its ancillary equipment. This can be done with the queued_exec decorator from customxepr.manager:

>>> import time
>>> from customxepr.manager import Manager
>>> manager = Manager()
>>> # create test function
>>> @manager.queued_exec
... def test_func(*args):
...     # do something
...     for i in range(0, 10):
...         time.sleep(1)
...         # check for requested aborts
...         if manager.abort.is_set():
...             break
...     return args  # return input arguments
>>> # run the function: this will return immediately
>>> test_func('test succeeded')

The result returned by test_func can be retrieved from the result queue as follows:

>>> result = manager.result_queue.get()  # blocks until result is available
>>> print(result)
test succeeded

More information regarding the manual scheduling of experiments can be found here.

Logging and error handling

The detection and escalation of possible problems is key to enabling unattended measurements. Otherwise the user may come back after two days expecting a completed measurement cycle, only to see that the helium dewar was emptied a day ago or that the program got stuck asking the user if it should really override a data file. CustomXepr therefore includes logging capabilities to track the progress of jobs and notify the user of potential problems.

All CustomXepr methods release logging messages during their execution which may have the levels “status”, “info”, “warning”, and “error”. Status notifications will only be shown in the user interface and typically contain information about the progress of a job (number of completed scans in an EPR measurement, countdown until the temperature is stable, etc). Info notifications typically contain information about the beginning or completion of a job (e.g., “Waiting for temperature to stabilize.”, “All scans complete.”), and potentially useful information about how the job was completed (e.g., “Temperature stable at 120.01±0.02 K during scans.”).

Warning notifications are logged when CustomXepr believes that there may be a problem which requires user intervention, for instance if a job is taking significantly longer than expected, or if the gas flow required to maintain a certain temperature is unusually high. Finally, error messages are released if CustomXepr is unable to proceed with a job, in which case it will abort and pause all pending jobs. Such errors may include loss of communication with an instrument, repeated strong temperature fluctuations during an EPR measurement, etc.

By default, all messages of level “info” and higher are saved to a log file in the user’s home directory and messages of level “warning” and higher are sent as an email to the user’s address. In addition, temperature readings are saved to a log file every 5 min, allowing the user to retrospectively confirm the temperature stability during measurements.

Screenshot of CustomXepr GUI

Mercury controls

CustomXepr includes a higher-level worker thread which regularly queries the MercuryiTC for its sensor readings and provides a live stream of this data to other parts of the software. This prevents individual functions from querying the MercuryiTC directly and causing unnecessary overhead.

The user interface for the cryostat plots historic temperature readings going back up to 24 h and provides access to relevant temperature control settings such as gas flow, heater power, and ramping speed while lower-level configurations such as calibration tables must be changed programmatically through the provided Jupyter console.

The MercuryiTC user interface and driver have been split off as separate packages mercuryitc and mercurygui.

Screenshot of Mercury GUI

Keithley controls

As with the cryostat, CustomXepr includes a high-level user interface for Keithley 2600 series instruments which allows the user to configure, record and save voltage sweeps such as transfer and output measurements. Since there typically is no need to provide a live stream of readings from the Keithley, the data from an IV-curve is buffered locally on the instrument and only transferred to CustomXepr after completion of a measurement.

The Keithley 2600 user interface and driver have been split off as separate packages keithley2600 and keithleygui.

Screenshot of Keithley GUI

Example code

A measurement script is given below which uses CustomXepr to cycles through different temperatures and records EPR spectra and transfer curves at each step. When run from an interactive Python console, it is possible to then uses the created customxepr instance to pause or resume and even abort running measurements.

from XeprAPI import Xepr
from keithley2600 import Keithley2600
from mercuryitc import MercuryITC
from customxepr import CustomXepr


# Connect to individual instruments.
xepr = Xepr()
mercury = MercuryITC("MERCURY_VISA_ADDRESS")
keithley = Keithley2600("KEITHLEY_VISA_ADDRESS")

# Create a new instance of CustomXepr to coordinate measurements.
customxepr = CustomXepr(xepr, mercury, keithley)

# Get a preconfigured experiment from Xepr.
exp = xepr.XeprExperiment('Experiment')

# Set up different modulation amplitudes in Gauss for different temperatures.
modAmp = {5: 3, 50: 2, 100: 1, 150: 1, 200: 1, 250: 1.5, 300: 2}

# Specify folder to save data.
folder = '/path/to/folder'
title = 'my_sample'

for T in [5, 50, 100, 150, 200, 250, 300]:

    # =================================================================
    # Prepare temperature
    # =================================================================

    customxepr.setTemperature(T)        # set desired temperature
    customxepr.customtune()             # tune the cavity
    customxepr.getQValueCalc(folder, T) # measure and save the Q factor

    # =================================================================
    # Perform FET measurements
    # =================================================================

    # Generate file name for transfer curve.
    transfer_file = '{}/{}_{}K_transfer.txt'.format(folder, title, T)
    # Record default transfer curve and save to file.
    customxepr.transferMeasurement(path=transfer_file)

    # =================================================================
    # Perform EPR measurements at Vg = -70V and Vg = 0V
    # =================================================================

    for Vg in [0, -70]:
        customxepr.setVoltage(Vg, smu='smua')  # bias gate
        # Perform preconfigured EPR measurement, save to file.
        esr_file = '{}/{}_{}K_Vg_{}V.txt'.format(folder, title, T, Vg)
        customxepr.runXeprExperiment(exp, path=esr_file, ModAmp=modAmp[T])
        customxepr.setVoltage(0, smu='smua')  # set gate voltage to zero

customxepr.setStandby()  # Ramp down field and set MW bridge to standby.

In this code, all functions belonging to CustomXepr will be added to the job queue and will be carried out successively such that, for instance, EPR measurements will not start while the temperature is still being ramped. Note that this example script will not load a graphical user interface.

Email notifications

By default, email notifications are sent from ‘customxepr@outlook.com’. CustomXepr at the moment provides no way to modify the email settings via the user interface, but you can set them manually in the config file in your home directory: ‘~/.CustomXepr/CustomXepr.ini’. Changes will be applied when restarting CustomXper.

By default, the relevant section in the config file reads:

[SMTP]
mailhost = localhost
port = 0
fromaddr = ss2151@cam.ac.uk
credentials =
secure =

Authentication credentials can be specified as a tuple (username, password). To specify the use of a secure protocol (TLS), pass in a tuple for the secure argument. This will only be used when authentication credentials are supplied. The tuple will be either an empty tuple, or a single-value tuple with the name of a keyfile, or a 2-value tuple with the names of the keyfile and certificate file.

Requirements

System requirements:

  • Linux or macOS

  • Python 2.7 or 3.6 and higher

Recommended:

  • Bruker Xepr software with Python XeprAPI (required for EPR related functions), a Python 3 version of the API is available here

  • Postfix - mail transfer agent (required for email notifications from localhost)

Required python modules:

  • PyQt5 >= 5.9

Recommended python modules:

  • pyusb (only when using pyvisa-py backend)

  • pyserial (only when using pyvisa-py backend)

Acknowledgements

  • Config modules are based on the implementation from Spyder.

  • Scientific spin boxes are taken from qudi.

Modules

This section gives an overview of CustmoXepr’s modules:

CustomXepr

@author: Sam Schott (ss2151@cam.ac.uk)

(c) Sam Schott; This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.0 UK: England & Wales License.

class main.CustomXepr(xepr=None, mercury=None, keithley=None)[source]

CustomXepr defines routines to control Bruker’s Xepr software and to run full ESR measurement cycles. When creating an instance of CustomXepr, you can pass instances of XeprAPI.XeprAPI, mercurygui.MercuryFeed and keithley2600.Keithley2600 to handle interactions with the respective instruments.

All CustomXepr methods that do not end with ‘_sync’ are executed in a worker thread in the order of their calls. Scheduling of jobs and retrieval of results is handled by manager.Manager. For instructions on how to schedule your own experiments, please refer to the documentation of manager.

Every asynchronous method has an equivalent method ending with ‘_sync’ which will be called immediately and block until it is done. Those synchronous equivalents are generated at runtime and not documented here.

You can use CustomXepr on its own, but it is recommended to start it with the function startup.run() in the startup module. This will automatically connect to available instruments and start CustomXepr’s graphical user interfaces.

Parameters
  • xepr – Xepr instance from the Bruker Python XeprAPI. Defaults to None if not provided.

  • mercuryfeedmercurygui.MercuryFeed instance for live feed from MercuryiTC temperature controller. Defaults to None if not provided.

  • keithleykeithley2600.Keithley2600 instance from keithley2600 driver. Defaults to None if not provided.

property notify_address

List with email addresses for status notifications.

property temp_wait_time

Wait time until temperature is considered stable. Defaults to 120 sec.

property temperature_tolerance

Temperature fluctuation tolerance. Defaults to 0.1 Kelvin.

static getExpDuration(exp)[source]

Estimates the time required to run the given experiment. The returned value is given in seconds and is a lower limit, the actual run time may be longer due to fine-tuning between scans, waiting times for stabilization and flybacks.

Parameters

exp – Xepr experiment object to run.

Returns

Estimated experiment duration in seconds.

Return type

float

Job scheduling

class manager.Manager[source]

Manager provides a high level interface for the scheduling and executing experiments. All queued experiments will be run in a background thread and Manager provides methods to pause, resume and abort the execution of experiments. All results will be kept in the result_queue for later retrieval.

Function calls can be queued as experiments by decorating the function with the Manager.queued_exec decorator:

>>> import time
>>> from customxepr.manager import Manager
>>> manager = Manager()
>>> # create test function
>>> @manager.queued_exec
... def decorated_test_func(*args):
...     # do something
...     for i in range(0, 10):
...         time.sleep(1)
...         # check for requested aborts
...         if manager.abort.is_set()
...             break
...     return args  # return input arguments
>>> # run the function: this will return immediately
>>> exp = decorated_test_func('test succeeded')

The result returned by test_func can be retrieved from the result queue or the returned Experiment instance:

>>> res1 = manager.result_queue.get()  # blocks until result is available
>>> res2 = exp.result()  # blocks until result is available
>>> print(res1)
test succeeded
>>> print(res1 is res2)
True

Alternatively, it is possible to manually create an experiment from a function call and queue it for processing as follows:

>>> import time
>>> from customxepr.manager import Manager, Experiment
>>> manager = Manager()
>>> # create test function
>>> def stand_alone_test_func(*args):
...     # do something
...     for i in range(0, 10):
...         time.sleep(1)
...         # check for requested aborts
...         if manager.abort.is_set()
...             break
...     return args  # return input arguments
>>> # create an experiment from function
>>> exp = Experiment(stand_alone_test_func, args=['test succeeded',], kwargs={})
>>> # queue the experiment
>>> manager.job_queue.put(exp)

This class provides an event abort which can queried periodically by any function to see if it should abort prematurely. Alternatively, functions and methods can provide their own abort events and register them with the manager as follows:

>>> from threading import Event
>>> abort_event = Event()
>>> # register the event with the manager instance
>>> manager.abort_events = [abort_event]

The manager will automatically set the status of an experiment to ABORTED if it finishes while an abort event is set and clear all abort events afterwards.

Variables
  • job_queue – An instance of ExperimentQueue holding all queued and finished experiments.

  • result_queue – A queue holding all results.

  • running – Event that causes the worker to pause between jobs if set.

  • abort – A generic event which can be used in long-running experiments to check if they should be aborted.

queued_exec(func)[source]

Decorator that puts a call to a wrapped function into the job_queue queue instead of executing it. Returns the queued Experiment which is similar to a Python’s concurrent.futures.Future.

pause_worker()[source]

Pauses the execution of jobs after the current job has been completed.

resume_worker()[source]

Resumes the execution of jobs.

abort_job()[source]

Aborts the current job and continues with the next.

clear_all_jobs()[source]

Clears all pending jobs in job_queue.

property notify_address

List of addresses for email notifications.

property log_file_dir

Directory for log files. Defaults to ‘~/.CustomXepr’.

property email_handler_level

Logging level for email notifications. Defaults to logging.WARNING.

class manager.Experiment(func, args, kwargs)[source]

Class to hold a scheduled job / experiment and keep track of its status and result. It is similar in functionality to concurrent.futures.Future.

Parameters
  • func – Function or method to call when running experiment.

  • args – Arguments for function call.

  • kwargs – Keyword arguments for function call.

running()[source]

Returns True if the job is running.

done()[source]

Returns True if the job is done, has failed or has been cancelled.

result(timeout=None)[source]

Returns the result of the experiment. If the experiment hasn’t yet completed then this method will wait up to timeout seconds. If the experiment hasn’t completed in timeout seconds, then a TimeoutError will be raised. If timeout is not specified or None, there is no limit to the wait time.

If the experiment is cancelled before completing then CancelledError will be raised.

If the call raised, this method will raise the same exception.

Parameters

timeout (int) – Time in seconds to wait for a result.

Raises

TimeoutError if no result becomes available within timeout, CancelledError if the experiment has been cancelled or Exception if an exception occurred during execution.

property status

Property that holds the status of the job.

class manager.ExpStatus(value)[source]

Enumeration to hold experiment status.

class manager.ExperimentQueue[source]

Queue to hold all jobs: Pending, running and already completed. Items in this queue should be of type Experiment.

Variables
  • added_signal – Emitted when a new job is added to the queue.

  • removed_signal – Emitted when a job is removed from the queue. Carriers the index of the job in ExperimentQueue.

  • status_changed_signal – Emitted when a job status changes, e.g., from ExpStatus.QUEUED to ExpStatus.RUNNING. Carries a tuple holding the job index and status.

property queue

Returns list of all items in queue (queued, running, and in history).

put(exp)[source]

Adds item exp to the end of the queue. Its status must be ExpStatus.QUEUED. Emits the added_signal signal.

get_next_job()[source]

Returns the next queued item and flags it as running. If there are no queued items, queue.Empty is raised. Emits the status_changed_signal with the item’s index and its new status.

job_done(exit_status, result=None)[source]

Call to inform the Experiment queue that a task is completed. Changes the corresponding item’s status to exit_status and its result to result. Emits the status_changed_signal with the item’s index and its new status.

Parameters
  • exit_status – Status of the completed job, i.e., ExpStatus.ABORTED.

  • result – Return value of job, if available.

remove_item(i)[source]

Removes the item with index i from the queue. Raises a ValueError if the item belongs to a running or already completed job. Emits the removed_signal carrying the index.

Parameters

i (int) – Index of item to remove.

remove_items(i_start, i_end=None)[source]

Removes the items from index i_start to i_end inclusive from the queue. Raises a ValueError if the item belongs to a running or already completed job. Emits the removed_signal for every removed item.

This call has O(n) performance with regards to the queue length and number of items to be removed.

Parameters
  • i_start (int) – Index of first item to remove.

  • i_end (int) – Index of last item to remove (defaults to i_end = i_start).

clear()[source]

Removes all queued experiments at once.

qsize(status=None)[source]

Return the approximate number of jobs with given status (not reliable!).

Parameters

status – Can be ‘queued’, ‘running’, ‘history’ or None. If None, the full queue size will be returned.

class manager.Worker(job_q, result_q, abort_events)[source]

Worker that gets all method calls with args from job_q and executes them. Results are then stored in the result_q.

Parameters
  • job_q – Queue with jobs to be performed.

  • result_q – Queue with results from completed jobs.

Variables

running – Event that causes the worker to pause between jobs if set.

Experiment

This section gives an overview of modules to handle and plot experimental EPR data. It contains two modules: experiment.xepr_dataset defines classes to read, write, manipulate and plot Xepr datasets from Bruker’s BES3T file format. mode_picture_dataset.xepr_dataset defines classes to read, write and plot cavity mode pictures.

This page documents the main classes available from experiment. The full API is documented in the pages for the respective submodules:

Xepr data module

@author: Sam Schott (ss2151@cam.ac.uk)

(c) Sam Schott; This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.0 UK: England & Wales License.

class experiment.xepr_dataset.XeprParam(name: str, value: Optional[Union[float, bool, str, numpy.ndarray]] = None, unit: str = '', comment: str = '')[source]

Bases: object

Holds a Bruker measurement parameter in the BES3T file format.

Parameters
  • value – The parameter value.

  • unit – String containing the unit. Defaults to an empty string.

  • comment – Defaults to an empty string.

to_string() str[source]

Prints a parameter as string in the Bruker BES3T format.

Returns

Parsed parameter.

from_string(string: str) None[source]

Parses a parameter from string given in the Bruker BES3T format.

Parameters

string (str) – String to parse.

class experiment.xepr_dataset.ParamGroup(name: str = '', pars: Optional[List[experiment.xepr_dataset.XeprParam]] = None)[source]

Bases: object

Class to hold an Xepr experiment parameter group, which is part of a layer.

Variables
  • HEADER_FMT – Format of parameter group header.

  • CELL_LENGTH – Length of cell containing the parameter name.

  • DELIM – Delimiter between parameter name and value.

Parameters
  • name – The parameter group’s name.

  • pars – Dictionary containing all XeprParam instances belonging to the group.

to_string() str[source]

Prints a parameter group as string.

from_string(string: str) None[source]

Parses a parameter group from given string.

Parameters

string – Parameter group string from Bruker .DSC file.

class experiment.xepr_dataset.ParamGroupDESC(name: str = '', pars: Optional[List[experiment.xepr_dataset.XeprParam]] = None)[source]

Bases: experiment.xepr_dataset.ParamGroup

Class to hold an Xepr experiment parameter group which forms a section of the Descriptor Layer (DESC).

class experiment.xepr_dataset.ParamGroupSPL(name: str = '', pars: Optional[List[experiment.xepr_dataset.XeprParam]] = None)[source]

Bases: experiment.xepr_dataset.ParamGroup

Class to hold an Xepr experiment parameter group associated with a functional unit, part of the Standard Parameter Layer (SPL).

HEADER_FMT = None
class experiment.xepr_dataset.ParamGroupDSL(name: str = '', pars: Optional[List[experiment.xepr_dataset.XeprParam]] = None)[source]

Bases: experiment.xepr_dataset.ParamGroup

Class to hold an Xepr experiment parameter group associated with a functional unit, part of the Device Specific Layer (DSL).

class experiment.xepr_dataset.ParamGroupMHL(name: str = '', pars: Optional[List[experiment.xepr_dataset.XeprParam]] = None)[source]

Bases: experiment.xepr_dataset.ParamGroup

Class to hold an Xepr experiment parameter group which forms a section of the Manipulation History Layer (MHL).

class experiment.xepr_dataset.ParamLayer(groups: Optional[List[experiment.xepr_dataset.ParamGroup]] = None)[source]

Bases: object

Parameter layer object. Contains a top level parameter section of a Bruker BES3T file. This should be subclassed, depending on the actual parameter layer type.

Variables
  • TYPE – Parameter layer type. Can be ‘DESC’ for a Descriptor Layer, ‘SPL’ for a Standard Parameter Layer, ‘DSL’ for a Device Specific Layer or ‘MHL’ for a Manipulation History Layer.

  • NAME – Parameter layer name.

  • VERSION – Parameter layer version. This identifies the implemented BES3T file format specification used when parsing the information.

  • HEADER_FMT – Header format for the parameter layer.

  • END – Characters to indicate the end of layer in ‘.DSC’ file.

GROUP_CLASS

alias of experiment.xepr_dataset.ParamGroup

to_string() str[source]

Prints the parameter layer as string.

Returns

Parameter layer string in as found in ‘.DSC’ file.

Return type

str

from_string(string: str) None[source]

Parses parameter layer string to contained parameters

Parameters

string (str) – Parameter layer string in as found in ‘.DSC’ file.

class experiment.xepr_dataset.DescriptorLayer(groups: Optional[List[experiment.xepr_dataset.ParamGroup]] = None)[source]

Bases: experiment.xepr_dataset.ParamLayer

Descriptor Layer class.

GROUP_CLASS

alias of experiment.xepr_dataset.ParamGroupDESC

class experiment.xepr_dataset.StandardParameterLayer(groups: Optional[List[experiment.xepr_dataset.ParamGroup]] = None)[source]

Bases: experiment.xepr_dataset.ParamLayer

Standard Parameter Layer class.

GROUP_CLASS

alias of experiment.xepr_dataset.ParamGroupSPL

from_string(string)[source]

Parses parameter layer string to contained parameters

Parameters

string (str) – Parameter layer string in as found in ‘.DSC’ file.

class experiment.xepr_dataset.DeviceSpecificLayer(groups: Optional[List[experiment.xepr_dataset.ParamGroup]] = None)[source]

Bases: experiment.xepr_dataset.ParamLayer

Device Specific Parameter Layer class.

GROUP_CLASS

alias of experiment.xepr_dataset.ParamGroupDSL

class experiment.xepr_dataset.ManipulationHistoryLayer(groups: Optional[List[experiment.xepr_dataset.ParamGroup]] = None)[source]

Bases: experiment.xepr_dataset.ParamLayer

Manipulation History Parameter Layer class.

GROUP_CLASS

alias of experiment.xepr_dataset.ParamGroupMHL

class experiment.xepr_dataset.Pulse(position: int, length: int, position_increment: int = 0, length_increment: int = 0)[source]

Bases: object

Object representing a single pulse.

Parameters
  • position – Pulse position in ns.

  • length – Pulse length in ns.

  • position_increment – Increment in pulse position between subsequent measurements in ns.

  • length_increment – Increment in pulse length between subsequent measurements in ns.

class experiment.xepr_dataset.PulseChannel(par: experiment.xepr_dataset.XeprParam)[source]

Bases: object

On object representing a pulse channel in a pulsed ESR experiment. Pulse channels can be for microwave pulses and acquisition (e.g., “+x”, “+y”, “AWG Trigger”, “Acquisition trigger”) which are manually set by the user or for instrument control pulses which are automatically determined (e.g., “TWT”, “”Receiver Protection”).

Every pulse channel can hold up to 1024 pulses, represented by Pulse instances.

Variables
  • N_PULSES_DEFAULT – Default number of programmable pulses: 400.

  • N_PULSES_MAX – Maximum number of programmable pulses 1024.

  • channel_descriptions – Verbose descriptions of pulse channels in a data file (otherwise designated by numbers Psd1 to Psd34 only).

Parameters

par – XeprParam holding the pulse channel table.

property name: str

Name of pulse channel, e.g., ‘Psd6’.

property number: int

Number of pulse channel, e.g., 6.

property description: str

Description of pulse channel, e.g., ‘+x’.

property pulses: List[experiment.xepr_dataset.Pulse]

List of pulses in this channel.

class experiment.xepr_dataset.PulseSequence(dset: experiment.xepr_dataset.XeprData)[source]

Bases: object

Object which hold information about the pulse sequence used to acquire the dataset (in case of pulsed experiments). This object is constructed from the pulse channel tables “Psd1”, “Psd2”, etc, in the descriptor layer.

property pulse_channels: List[experiment.xepr_dataset.PulseChannel]

Returns a list of pulse channels present in the instrument.

plot() None[source]

Plots the pulse sequence used to acquire the data.

Raises

RuntimeError if the experiment is not pulsed.

Raises

ImportError if matplotlib is not installed.

class experiment.xepr_dataset.ParamDict(layers: Dict[str, experiment.xepr_dataset.ParamLayer])[source]

Bases: collections.abc.MutableMapping

Object to allow attribute access to all measurement parameters.

class experiment.xepr_dataset.XeprData(path: Optional[str] = None)[source]

Bases: object

Holds a Bruker EPR measurement result, including all measurement parameters. Supports importing and exporting to the Bruker BES3T file format (‘.DSC’, ‘.DTA’ and possible associated ‘.XGF’, ‘.YGF’ and ‘.ZGF’ files) in the 1.2 specification currently used by Xepr. Parameters are stored in the following attributes and are grouped after the associated functional unit (e.g., ‘mwBridge’, ‘fieldCtrl’) or type (e.g., ‘Documentational Text’).

Variables
  • descDescriptorLayer instance holding the parameters from the ‘.DSC’ file that describe content and parsing of corresponding data files (‘.DTA’ etc).

  • splStandardParameterLayer instance holding all mandatory EPR parameters, such as the microwave power.

  • dslDeviceSpecificLayer instance holding the EPR measurement parameters specific to the instrument and type of measurement, i.e., the measurement temperature, sample angles, integration time, etc.

  • mhlManipulationHistoryLayer instance holding all parameters that describe manipulations performed on the data set (e.g., baseline correction, scaling, …).

  • pars – Dictionary-like object giving direct access to all measurement parameters. Allows for quickly reading and setting parameter values.

  • pulse_sequencePulseSequence instance which describes the pulse sequence used to acquire the data (in case of pulsed experiments). This object is constructed from the pulse channel tables “Psd1”, “Psd2”, etc, in the descriptor layer.

Setting the value of an existing parameter will automatically update it in the appropriate parameter layer. Setting a new parameter value will add it to a ‘customXepr’ device group in the DeviceSpecificLayer.

The actual data is accessible as numpy arrays x, y, z and o. Only the the ordinate data may be changed and the new data must have the same size and format as o. It is not currently possible to change the x/y/z-axis data.

Warning

Changing the parameters in the Descriptor Layer may result in inconsistencies between the parameter file (DSC) and the actual data files (DTA, XGF, YGF, ZGF) and therefore may result in corrupted files.

Examples

Read a data file and get some information about the device specific parameters:

>>> from customxepr import XeprData, XeprParam
>>> dset = XeprData("/path/to/file.DSC")
>>> dset.dsl.groups
{"fieldCtrl": <ParamGroupDSL(fieldCtrl)>,
 "fieldSweep": <ParamGroupDSL(fieldSweep)>,
 "freqCounter": <ParamGroupDSL(freqCounter)>,
 "mwBridge": <ParamGroupDSL(mwBridge)>,
 "recorder": <ParamGroupDSL(recorder)>,
 "signalChannel": <ParamGroupDSL(signalChannel)>}
>>> dset.dsl.groups["mwBridge"].pars
{"AcqFineTuning": <XeprParam(Never)>,
 "AcqScanFTuning": <XeprParam(Off)>,
 "AcqSliceFTuning": <XeprParam(Off)>,
 "BridgeCalib": <XeprParam(50.5)>,
 "Power": <XeprParam(0.002 mW)>,
 "PowerAtten": <XeprParam(50.0 dB)>,
 "QValue": <XeprParam(5900)>}

Change the value of an existing parameter:

>>> dset.pars["ModAmp"].value = 2

Add a new parameter without an associated group (it will be added to a “CustomXepr” group in the DSL layer):

>>> dset.pars["NewParam"] = XeprParam("NewParam", 1234)

Add a new parameter to the microwave bridge device group:

>>> dset.dsl.groups["mwBridge"].add_param(XeprParam("QValue", 6789))

Add a new parameter group for a temperature controller, with two parameters:

>>> pars = [
...    XeprParam("Temperature", 290, "K"),
...    XeprParam("AcqWaitTime", 120, "s")
...    ]
>>> new_group = ParamGroupDSL("tempCtrl", pars)
>>> dset.dsl.groups["tempCtrl"] = new_group

Save the modified data set:

>>> dset.save("/path/to/file.DSC")
property x: numpy.ndarray

Returns x-axis data as numpy array.

property y: numpy.ndarray

Returns y-axis data as numpy array.

property z: numpy.ndarray

Returns z-axis data as numpy array.

property o: numpy.ndarray

Returns ordinate data as numpy array or as a tuple of arrays containing all ordinate data sets. If real and imaginary parts are present, they will be combined to a complex numpy array.

load(path: str) None[source]

Loads data and parameters from a ‘.DSC’ file and accompanying data files.

Parameters

path (str) – Path to ‘.DSC’ file or accompanying data files to load. Any of those file paths can be given, the other files belonging to the same data set will be found automatically if in the same directory.

save(path: str) None[source]

Saves data and parameters to a ‘.DSC’ file and accompanying data files.

Parameters

path (str) – Path to ‘.DSC’ file or accompanying data files to save. Any of those file paths can be given, the other file names will be generated as necessary.

print_dsc() str[source]

Parses all parameters as ‘.DSC’ file content and returns the result as a string.

Returns

String containing all parameters in ‘.DSC’ file format.

Return type

str

plot() None[source]

Plots all recorded spectra / sweeps as 2D or 3D plots. Requires matplotlib.

Mode picture module

@author: Sam Schott (ss2151@cam.ac.uk)

(c) Sam Schott; This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.0 UK: England & Wales License.

experiment.mode_picture_dataset.lorentz_peak(x, x0, w, a)[source]

Lorentzian with area a, full-width-at-half-maximum w, and center x0.

class experiment.mode_picture_dataset.ModePicture(input_path_or_data, freq=9.385, metadata=None)[source]

Class to store mode pictures. It provides methods to calculate Q-values, and save and load mode picture data from and to .txt files.

If several mode pictures with different zoom factors are given, ModePicture will rescale and combine the data into a single mode picture.

Parameters
  • input_path_or_data (dict) – Dict with zoom factors as keys and respective mode picture data sets as values or path to file with saved mode picture data.

  • freq (float) – Cavity resonance frequency in GHz as float.

  • metadata (dict) – Optional dictionary with metadata to save in the file header.

Variables
  • x_data_mhz – Numpy array with x-axis data of mode picture in MHz.

  • x_data_points – Numpy array with x-axis data of mode picture in pts.

  • y_data – Mode picture y-axis data (absorption of cavity).

  • freq0 – Center frequency of cavity resonance.

  • qvalue – Fitted Q-Value.

  • qvalue_stderr – Standard error of Q-Value from fitting.

combine_data(mode_pic_data)[source]

Rescales mode pictures from different zoom factors and combines them to one.

Parameters

mode_pic_data (dict) – Dict with zoom factors as keys and respective mode picture curves as values.

Returns

(x_axis_mhz_comb, x_axis_points_comb, mode_pic_comb) where x_axis_mhz_comb and x_axis_points_comb are the combined x-axis values of all mode pictures in mhz and points, respectively, and mode_pic_comb is the combines y-axis data in a.u..

fit_qvalue(x_data, y_data, zoom_factor=1)[source]

Least square fit of Lorentzian and polynomial background to mode picture.

Parameters
  • x_data – Iterable containing x-data of mode picture in points.

  • y_data – Iterable containing y-data of mode picture in a.u..

  • zoom_factor – Zoom factor (scaling factor of x-axis).

Returns

(q_value, fit_result) where fit_result is a

get_qvalue_stderr()[source]

Determines 1 sigma confidence bounds for Q-value.

Returns

Standard error of Q-value from fitting.

Return type

float

plot()[source]

Plots mode picture and the least squares fit used to determine the Q-value. Requires matplotlib.

save(filepath)[source]

Saves mode picture data as a text file with headers. If no file path is given, the user is prompted to select a location and name through a user interface.

Parameters

filepath (str) – Absolute file path.

load(path)[source]

Loads mode picture data from text file and determines the resulting Q-factor.

Parameters

path (str) – Path of file.

class experiment.XeprData(path: Optional[str] = None)[source]

Holds a Bruker EPR measurement result, including all measurement parameters. Supports importing and exporting to the Bruker BES3T file format (‘.DSC’, ‘.DTA’ and possible associated ‘.XGF’, ‘.YGF’ and ‘.ZGF’ files) in the 1.2 specification currently used by Xepr. Parameters are stored in the following attributes and are grouped after the associated functional unit (e.g., ‘mwBridge’, ‘fieldCtrl’) or type (e.g., ‘Documentational Text’).

Variables
  • descDescriptorLayer instance holding the parameters from the ‘.DSC’ file that describe content and parsing of corresponding data files (‘.DTA’ etc).

  • splStandardParameterLayer instance holding all mandatory EPR parameters, such as the microwave power.

  • dslDeviceSpecificLayer instance holding the EPR measurement parameters specific to the instrument and type of measurement, i.e., the measurement temperature, sample angles, integration time, etc.

  • mhlManipulationHistoryLayer instance holding all parameters that describe manipulations performed on the data set (e.g., baseline correction, scaling, …).

  • pars – Dictionary-like object giving direct access to all measurement parameters. Allows for quickly reading and setting parameter values.

  • pulse_sequencePulseSequence instance which describes the pulse sequence used to acquire the data (in case of pulsed experiments). This object is constructed from the pulse channel tables “Psd1”, “Psd2”, etc, in the descriptor layer.

Setting the value of an existing parameter will automatically update it in the appropriate parameter layer. Setting a new parameter value will add it to a ‘customXepr’ device group in the DeviceSpecificLayer.

The actual data is accessible as numpy arrays x, y, z and o. Only the the ordinate data may be changed and the new data must have the same size and format as o. It is not currently possible to change the x/y/z-axis data.

Warning

Changing the parameters in the Descriptor Layer may result in inconsistencies between the parameter file (DSC) and the actual data files (DTA, XGF, YGF, ZGF) and therefore may result in corrupted files.

Examples

Read a data file and get some information about the device specific parameters:

>>> from customxepr import XeprData, XeprParam
>>> dset = XeprData("/path/to/file.DSC")
>>> dset.dsl.groups
{"fieldCtrl": <ParamGroupDSL(fieldCtrl)>,
 "fieldSweep": <ParamGroupDSL(fieldSweep)>,
 "freqCounter": <ParamGroupDSL(freqCounter)>,
 "mwBridge": <ParamGroupDSL(mwBridge)>,
 "recorder": <ParamGroupDSL(recorder)>,
 "signalChannel": <ParamGroupDSL(signalChannel)>}
>>> dset.dsl.groups["mwBridge"].pars
{"AcqFineTuning": <XeprParam(Never)>,
 "AcqScanFTuning": <XeprParam(Off)>,
 "AcqSliceFTuning": <XeprParam(Off)>,
 "BridgeCalib": <XeprParam(50.5)>,
 "Power": <XeprParam(0.002 mW)>,
 "PowerAtten": <XeprParam(50.0 dB)>,
 "QValue": <XeprParam(5900)>}

Change the value of an existing parameter:

>>> dset.pars["ModAmp"].value = 2

Add a new parameter without an associated group (it will be added to a “CustomXepr” group in the DSL layer):

>>> dset.pars["NewParam"] = XeprParam("NewParam", 1234)

Add a new parameter to the microwave bridge device group:

>>> dset.dsl.groups["mwBridge"].add_param(XeprParam("QValue", 6789))

Add a new parameter group for a temperature controller, with two parameters:

>>> pars = [
...    XeprParam("Temperature", 290, "K"),
...    XeprParam("AcqWaitTime", 120, "s")
...    ]
>>> new_group = ParamGroupDSL("tempCtrl", pars)
>>> dset.dsl.groups["tempCtrl"] = new_group

Save the modified data set:

>>> dset.save("/path/to/file.DSC")
property x: numpy.ndarray

Returns x-axis data as numpy array.

property y: numpy.ndarray

Returns y-axis data as numpy array.

property z: numpy.ndarray

Returns z-axis data as numpy array.

property o: numpy.ndarray

Returns ordinate data as numpy array or as a tuple of arrays containing all ordinate data sets. If real and imaginary parts are present, they will be combined to a complex numpy array.

load(path: str) None[source]

Loads data and parameters from a ‘.DSC’ file and accompanying data files.

Parameters

path (str) – Path to ‘.DSC’ file or accompanying data files to load. Any of those file paths can be given, the other files belonging to the same data set will be found automatically if in the same directory.

save(path: str) None[source]

Saves data and parameters to a ‘.DSC’ file and accompanying data files.

Parameters

path (str) – Path to ‘.DSC’ file or accompanying data files to save. Any of those file paths can be given, the other file names will be generated as necessary.

print_dsc() str[source]

Parses all parameters as ‘.DSC’ file content and returns the result as a string.

Returns

String containing all parameters in ‘.DSC’ file format.

Return type

str

plot() None[source]

Plots all recorded spectra / sweeps as 2D or 3D plots. Requires matplotlib.

class experiment.XeprParam(name: str, value: Optional[Union[float, bool, str, numpy.ndarray]] = None, unit: str = '', comment: str = '')[source]

Holds a Bruker measurement parameter in the BES3T file format.

Parameters
  • value – The parameter value.

  • unit – String containing the unit. Defaults to an empty string.

  • comment – Defaults to an empty string.

to_string() str[source]

Prints a parameter as string in the Bruker BES3T format.

Returns

Parsed parameter.

from_string(string: str) None[source]

Parses a parameter from string given in the Bruker BES3T format.

Parameters

string (str) – String to parse.

class experiment.ModePicture(input_path_or_data, freq=9.385, metadata=None)[source]

Class to store mode pictures. It provides methods to calculate Q-values, and save and load mode picture data from and to .txt files.

If several mode pictures with different zoom factors are given, ModePicture will rescale and combine the data into a single mode picture.

Parameters
  • input_path_or_data (dict) – Dict with zoom factors as keys and respective mode picture data sets as values or path to file with saved mode picture data.

  • freq (float) – Cavity resonance frequency in GHz as float.

  • metadata (dict) – Optional dictionary with metadata to save in the file header.

Variables
  • x_data_mhz – Numpy array with x-axis data of mode picture in MHz.

  • x_data_points – Numpy array with x-axis data of mode picture in pts.

  • y_data – Mode picture y-axis data (absorption of cavity).

  • freq0 – Center frequency of cavity resonance.

  • qvalue – Fitted Q-Value.

  • qvalue_stderr – Standard error of Q-Value from fitting.

combine_data(mode_pic_data)[source]

Rescales mode pictures from different zoom factors and combines them to one.

Parameters

mode_pic_data (dict) – Dict with zoom factors as keys and respective mode picture curves as values.

Returns

(x_axis_mhz_comb, x_axis_points_comb, mode_pic_comb) where x_axis_mhz_comb and x_axis_points_comb are the combined x-axis values of all mode pictures in mhz and points, respectively, and mode_pic_comb is the combines y-axis data in a.u..

fit_qvalue(x_data, y_data, zoom_factor=1)[source]

Least square fit of Lorentzian and polynomial background to mode picture.

Parameters
  • x_data – Iterable containing x-data of mode picture in points.

  • y_data – Iterable containing y-data of mode picture in a.u..

  • zoom_factor – Zoom factor (scaling factor of x-axis).

Returns

(q_value, fit_result) where fit_result is a

get_qvalue_stderr()[source]

Determines 1 sigma confidence bounds for Q-value.

Returns

Standard error of Q-value from fitting.

Return type

float

plot()[source]

Plots mode picture and the least squares fit used to determine the Q-value. Requires matplotlib.

save(filepath)[source]

Saves mode picture data as a text file with headers. If no file path is given, the user is prompted to select a location and name through a user interface.

Parameters

filepath (str) – Absolute file path.

load(path)[source]

Loads mode picture data from text file and determines the resulting Q-factor.

Parameters

path (str) – Path of file.

Startup

Created on Tue Aug 23 11:03:57 2016

@author: Sam Schott (ss2151@cam.ac.uk)

(c) Sam Schott; This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.0 UK: England & Wales License.

startup.show_splash_screen()[source]

Shows the CustomXepr splash screen.

Returns

PyQt5.QtWidgets.QSplashScreen.

startup.connect_to_instruments()[source]

Tries to connect to Keithley, Mercury and Xepr. Uses the visa addresses saved in the respective configuration files.

Returns

Tuple containing instrument instances.

Return type

tuple

startup.start_gui(customXepr, mercury, keithley)[source]

Starts GUIs for Keithley, Mercury and CustomXepr.

Returns

Tuple containing GUI instances.

Return type

tuple

startup.run_cli()[source]

This is the main interactive shell entry point. Calling run_cli will connect to all instruments and return instantiated control classes.

Returns

Tuple containing instrument instances.

Return type

tuple

startup.run_gui()[source]

Runs the CustomXepr GUI – this is the main entry point. Calling run_gui will first create a Qt application, then aim to connect to Xepr, a Keithley2600 instrument and a MercuryiTC temperature controller and finally create user interfaces to control all three instruments.

startup.run_ip()[source]

Runs the CustomXepr GUI from IPython.

Changelog

v3.1.3

Fixed:

  • Fixed spurious notifications from log messages emitted outside of customxepr.

v3.1.2

Added:

  • Added support to parse and plot the pulse sequence information stored in the Bruker DSC file in the tables Psd1 to Psd36:

    >>> from customxepr.experiment import XeprData
    >>> dset = XeprData("path")
    >>> dset.pulse_sequence.plot()
    >>> print(dset.pulse_sequence.pulse_channels[5])
    <PulseChannel(Psd6: +x)>
    >>> print(dset.pulse_sequence.pulse_channels[5].pulses)
    [<Pulse(position=276, length=4)>, <Pulse(position=676, length=44)>]
    
  • Added a keyword argument settling_time to runXeprExperiment to wait between individual scans. This can be useful in case of temperature fluctuations between scans.

Changed:

  • Remove custom exit_customxepr() function. Instead, close the console to exit CustomXepr or run exit when started from an IPython or Jupyter shell.

  • Increase default maximum cooling temperature to 20°C.

  • Remember the location of the console window between restarts.

  • Set current directory of Xepr to directory of last-saved data.

  • The Qt event loop is no longer started on every import but just when actually starting the GUI or plotting a figure.

  • getValueXepr no longer accepts a path argument.

  • getQValueCalc no longer saves two files but the mode picture only. The given path must now be the full file path. The temperature data will now be saved together with the mode picture.

  • getQValueCalc no longer accepts a temperature argument. Instead, the temperature will be read from the Mercury if available.

  • The ModePicture class now accepts arbitrary metadata in dictionary form. This data will be saved as tab-delimited metadata in the mode picture file.

Fixed:

  • Fixed an issue when saving a dateset through Xepr when the path contains whitespace or backslashes. The path is now quoted with shlex.quote before being passed to Xepr.

v3.1.1

Changed:

  • Only show single-line previews of results in GUI.

  • Improve warnings for too high gasflow.

  • Allow overriding default tolerance and wait time in waitTemperatureStable.

Added:

  • Monitor cooling water temperature during measurements and interrupt ESR measurements if too high.

  • Added config file entries for the maximum cooling temperature and the temperature sensor names for the ESR and cooling water.

Fixed:

  • Fixes an issue in customxepr.experiment.xepr_dataset.XeprParam where the unit attribute would return the value instead of the unit.

v3.1.0

Added:

  • Added API similar to concurrent.futures.Future to customxepr.manager.Experiment.

  • Return an experiment instance from all async customxepr method calls. This instance can be used to get the result directly, instead of getting it from the result queue. Usage:

    future = customXepr.runXeprExperiment(...)
    result = future.result()  # will block until result is available
    

Changed:

  • CustomXepr.tune and CustomXepr.finetune can now be aborted.

  • ModePicture.load(...) no longer returns the raw data but rather populates the class attributes of ModePicture with the loaded data.

  • XeprData now shows the experiment title in its string representation.

  • Changed the default email address for notifications to physics-oe-esr-owner@lists.cam.ac.uk.

  • Improvements to documentation.

  • Require PyQt5 instead of qtpy / PySide2.

Fixed:

  • Fixes an issue where CustomXepr.tune and CustomXepr.finetune would return immediately, even if tuning was not complete.

v3.0.0

This release drops support for Python 2.7. Only Python 3.6 and higher are supported.

Added:

  • Method CustomXepr.getExpDuration to estimate the duration of an Xepr experiment.

  • Added synchonous functions for all of CustomXepr’s asynchronous functions (which will be queued). These are automatically generated and end with the suffix “_sync”.

  • Added shape attribute to XeprData class.

Changed:

  • Changed the abort behaviour of a measurement: Instead of finishing the current scan and pausing afterwards, the scan is aborted immediately.

  • Renamed setDrainCurrent to setCurrent and setGateVoltage to setVoltage.

  • setVoltage no longer turns the other SMUs off.

  • Optimized the truncation of long items in the list of running expriements.

  • Changed the priority of locations to search for the XeprAPI:
    1. path from the environment variable XEPR_API_PATH (if set)

    2. installed python packages

    3. pre-installed version from Xepr

  • Renamed applyCurrent to setCurrent.

  • The queued_exec decorator is now an attribute of customXepr.manager.Manager and no longer requires the job queue as an argument. Instead, the manager’s job_queue will be used automatically.

  • The queued_exec decorator now is re-entrant: decorated functions which are called from within the worker thread won’t be queued themselves.

  • Moved CustomXepr._wait_stable to a public method CustomXepr.waitTemperatureStable.

  • Enforce usage of exit_customxepr() to exit.

  • Set the default address for email notifications to ‘physics-oe-esr-owner@lists.cam.ac.uk’.

  • Increased the default timeout for PyVisa communication from 2 sec to 5 sec.

Fixed:

  • Fixed a bug when plotting aquired results: This was related to the IPython kernel or the interactive console using the wrong GUI backend. It now uses the Qt backend.

  • Fixed a bug which would cause XeprData.plot to fail in case of multiple datasets per scan, e.g., for simultanious detection of the in-phase and out-of-phase signals.

  • Fixed several Python 3 compatibility issues.

Removed:

  • Support for Python 2.7. Only Python 3.6 and higher will be supported. Please migrate.

v2.3.4 (2019-10-09)

Main changes are:

  • Possible file names for Xepr data are no longer limited by Xepr’s file name restrictions.

  • Added a function exit_customxepr which gracefully disconnects all instruments before quitting the Python console. This avoids errors on the next startup.

  • Bug fixes.

In more detail:

Added:

  • Added a function exit_customxepr which gracefully disconnects all instruments and then exits the Python console. This avoids errors on the next startup.

  • Added a help button to the main UI, replacing the copyright notice.

  • Added support for dark interface themes, such as dark mode in macOS Mojave. This requires a version of PyQt / Qt which supports system themes, e.q. PyQt 5.12+ for macOS.

Changed:

  • Changed how Xepr data is saved: CustomXepr will now always save to a temporary file first which is guaranteed to comply with Xepr’s file name restrictions. This temporary file will then be reloaded to add custom parameters and will be saved through Python to any path which the file system accepts.

  • If CustomXepr is not started from an IPython console, use an in-process IPython kernel and Jupyter console widget for user interactions. This gives us better control over the appearance of the console widget.

  • Removed pyqrgraph dependency.

Fixed:

  • Fixed a bug which could cause customXepr.setGateVoltage() and subsequent Keithley commands to fail due to an invalid command sent to the Keithley.

  • Fixed a bug which would cause queued function calls without any arguments not to show in the job queue window.

  • Fixed a bug which would prevent the phase from being cycled by 360 deg when hitting the upper or lower limit during a tuning routine.

v2.3.3 (2019-07-15)

This release focuses on minor UI improvements. The most notable change is a better handling of Bruker data files: the order of entries in DSC files is preserved when saving through CustomXepr.

Changed:

  • Small tweaks to dialog windows (update info, about window, etc.).

  • Preserve order of entries in DSC files in Python 2. Previously, the order of sections and parameter would be randomized when loading and saving a Bruker DSC files with CustomXepr in Python 2.7.

  • Moved some custom widgets which are shared between customxepr, keithleygui and mercurygui to a common submodule pyqt_labutils.

v2.3.2 (2019-05-25)

Improves compatibility of XeprData with Bruker’s Xepr BES3T file format: support complex data and more exotic data formats.

Added:

  • Expanded support for Xepr data files: introduced support for complex data sets, 32-bit floats and 32-bit signed integers as well as multiple ordinate data sets per data file.

  • Introduced support for different byte-orders, as specified in ‘.DSC’ file.

  • Save the standard error from fitting the Q-Value as a new parameter ‘QValueErr’ in the DSC file, if available.

  • Allow configuration of a custom SMTP server for email notifications in the config file ‘~/.CustomXepr/CustomXepr.ini’.

Changed:

  • Improved the usefulness of some log messages.

  • Keep measurement logs for 356 days instead of 7 days.

  • Improved formatting of DSC files saved through CustomXepr vs Xepr. Number formatting, e.g., the number of significant digits, will be preserved unless the parameter value has changes

Fixed:

  • Fixed a bug in XeprData which would save y-axis and z-axis data files with the wrong byte-order. Ordinate data and x-axis data were not affected. Xepr expects data files to be saved with the byte-order specified in the DSC file (typically big-endian).

  • Fixed a bug in XeprData when saving the ‘PolyCof’ parameter or other array data to DSC files: The array shape would be incorrectly saved in the header (with row and column numbers swapped).

  • Fixed a deadlock when removing an item from the result queue.

  • Fixed an issue where the job status icons might not update until the user clicks on the CustomXepr window.

v2.3.1 (2019-04-23)

This release adds several options (keyword arguments) to CustomXepr functions. It also fully separates UI from non-UI modules.

Added:

  • Double click on a result in the GUI to plot it.

  • Enable editing of ordinate data in XeprData instance.

  • Added a keyword argument low_q to customtune to enable tuning with low Q-values (default: low_q=False).

  • Added a keyword argument auto_gf to setTemperature to disable or enable automatic gas flow control (default: auto_gf=True).

  • Added a keyword argument htt_file to heater_target to select a file with a custom heater target table.

Changed:

  • Simplified access and modification of XeprData parameters. Parameter values can now be updated directly by assigning a value to their dictionary entry.

  • Updated default heater target table for MercuryITC.

  • Log files older than 7 days are deleted automatically on startup.

  • Removed all Qt related dependencies from non-GUI modules. This makes it easier to run CustomXepr in headless mode from the command line.

Removed:

  • Deprecated set_param and get_param methods of XeprData. Use the pars attribute with dictionary type access instead.

v2.3.0 (2019-03-20)

This release focuses on under-the-hood improvements and provides significant speedups to the user interface (plotting data, deleting a large number of queued jobs, etc).

Changed:

  • Reduced the startup time when no instruments can be found.

  • Added info messages to the splash screen.

  • Switched plotting library for Mercury ITC and Keithley 2600 from Matplotlib to pyqtgraph. This allows for smoother user interactions with plots.

  • Performance improvements when deleting a large number of results or pending jobs: previously O(n^2), now O(n) performance.

  • Better organization of code into submodules.

Fixed:

  • Bug fixes for PyQt 5.12.

v2.2.2 (2019-02-19)

This release adds support for reading and writing Bruker Xepr data files in the BES3T format.

Added:

  • Added XeprData class to hold, read and save Xepr measurement data files. XeprData provides methods to access and modify measurement parameters and to plot the data. It is compatible with all Xepr experiment types, saved in the Bruker BES3T file format up to version 1.2 (currently used by Xepr).

Changed:

  • runXeprExperiment now accepts a path parameter. If given, the resulting data will be saved to the specified path, together with the last-measured Q-value and temperature set point.

  • Tweaked icons in user interface.

Removed:

  • Removed the option to specify a title when saving an ESR data file. The file name is now always used as title.

  • saveCurrentData will be removed in a future version of CustomXepr. Use the path keyword of runXeprExperiment to save the measurement data instead.

v2.2.1 (2019-01-25)

This release introduces online documentation for CustomXepr and user includes interface improvements.

Added:

Changed:

  • Switched from custom TslSMTPHandler to python-bundled SMTPHandler for email notifications.

  • Improved docstrings.

v2.2.0 (2019-01-09)

Added:

  • Added terminal / command line script “CustomXepr”.

  • Added confidence interval for Q-value calculation in ModePicture class.

  • Window positions and sizes are saved and restored between sessions.

  • Show errors during job execution in GUI in addition to email notifications.

  • Nicely colored trace backs for error messages.

Changed:

  • CustomXepr is now distributed as a python package and can be installed with pip.

Fixed:

  • Fixed a bug that could result in values inside spin-boxes to be displayed without their decimal marker on some systems.

  • Fixed a bug that could result in crashes after closing the keithley or mercury control windows.

Removed:

  • Removed all ETA estimates for experiments.

v2.1.1

Added:

  • Included revamped keithleygui with IV sweep functionality.

  • Compatibility with Python 3.6 and higher.

Changed:

  • Proper disconnection from instruments when closing windows or shutting down the console with “exit” command.

Fixed:

  • Fixed a bug that would prevent Xepr experiments to run if the measurement time cannot be estimated. Applies for instance to rapid scan and time domain measurements where proper ETA estimates have not yet been implemented.

v2.1.0

Added:

  • Warnings when invalid file paths are handed to Xepr.

Changed:

  • Split off mercury_gui and keithley_gui as separate packages.

Removed:

  • Removed dark theme: code is easier to maintain. System level dark themes, such as macOS Mojave’s dark mode, may be supported in the future when Qt support is added.

v2.0.1

Changed:

  • Moved default driver backends from NI-VISA to pyvisa-py. It is no longer necessary to install NI-VISA from National Instruments on your system.

  • Moved drivers to external packages. Install with pip before first use.

  • Improved data plotting in Mercury user interface:

    • heater output and gas flow are plotted alongside the temperature

    • major speedups in plotting frame rate by relying on numpy for updating the data and redrawing only changed elements of plot widget

    • allow real-time panning and zooming of plots

  • Started working on Python 3 compatibility.

Indices and tables