diff --git a/.github/workflows/Build_Deploy_Docs.yml b/.github/workflows/Build_Deploy_Docs.yml index 353f287..a8070f3 100644 --- a/.github/workflows/Build_Deploy_Docs.yml +++ b/.github/workflows/Build_Deploy_Docs.yml @@ -28,6 +28,7 @@ jobs: run: poetry run sphinx-build -b html docsrc/ docsrc/_build/html > sphinx_build.log 2>&1 - name: Upload build log uses: actions/upload-artifact@v4.6.2 + if: always() with: name: sphinx-build-log path: sphinx_build.log diff --git a/.github/workflows/TestBuild_Docs.yml b/.github/workflows/TestBuild_Docs.yml new file mode 100644 index 0000000..df5bf6a --- /dev/null +++ b/.github/workflows/TestBuild_Docs.yml @@ -0,0 +1,39 @@ +name: Test Build Docs + +on: + push: + branches: + - develop + - main + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.12' + + - name: Install Poetry + run: | + curl -sSL https://install.python-poetry.org | python - + echo "${HOME}/.local/bin" >> $GITHUB_PATH + + - name: Install dependencies + run: poetry install --with doc + + - name: Build documentation + run: poetry run sphinx-build -b html docsrc/ docsrc/_build/html > sphinx_build.log 2>&1 + - name: Upload build log + uses: actions/upload-artifact@v4.6.2 + if: always() + with: + name: sphinx-build-log + path: sphinx_build.log + diff --git a/.gitignore b/.gitignore index a720cb0..50aa696 100644 --- a/.gitignore +++ b/.gitignore @@ -105,6 +105,7 @@ venv/ ENV/ env.bak/ venv.bak/ +.venv* # Spyder project settings .spyderproject @@ -125,3 +126,7 @@ dmypy.json .pyre/ .DS_Store + +poetry.lock + +docsrc/auto_examples/ diff --git a/citation.rst b/citation.rst new file mode 100644 index 0000000..aecb3c1 --- /dev/null +++ b/citation.rst @@ -0,0 +1,39 @@ +Citation +-------- + +Citation of scientific software is important to give credit to the developers and to help track the impact of the software in research. + +To cite PyEPR in publications, please currently use the Zenodo general DOI: + +.. image:: https://zenodo.org/badge/888368760.svg + :target: https://doi.org/10.5281/zenodo.17107010 + :alt: DOI + +Specific PyEPR versions will also have uniquie DOIs that can be found on the respective Zenodo release page. +The associated Zotero entry is available `here `_. + +A paper describing PyEPR is currently in preparation and will be linked here once published. + +Bibtex Entry +++++++++++++ + +.. code-block:: bibtex + + @software{pyepr_2025, + author = {Hugo, Karas and + Jeschke, Gunnar and + Stoll, Stefan}, + title = {JeschkeLab/PyEPR: Version 1.0}, + month = sep, + year = 2025, + publisher = {Zenodo}, + version = {v1.0}, + doi = {10.5281/zenodo.17107011}, + url = {https://doi.org/10.5281/zenodo.17107011}, + swhid = {swh:1:dir:d3ae7fdd8041eb365003ea3e40db8bbb31a6c741 + ;origin=https://doi.org/10.5281/zenodo.17107010;vi + sit=swh:1:snp:5c1894da8cabcaf89397959130c3ff4badea + 5b87;anchor=swh:1:rel:316cb6fc9c055bd7058460f5559a + 8342d326ebd4;path=JeschkeLab-PyEPR-c194a75 + }, + } diff --git a/docsrc/API_docs.rst b/docsrc/API_docs.rst index 2d26e95..2c625c4 100644 --- a/docsrc/API_docs.rst +++ b/docsrc/API_docs.rst @@ -19,6 +19,7 @@ Analysis Modules .. autoapisummary:: pyepr.FieldSweepAnalysis + pyepr.HahnEchoRelaxationAnalysis pyepr.ResonatorProfileAnalysis pyepr.CarrPurcellAnalysis pyepr.ReptimeAnalysis @@ -29,7 +30,7 @@ Sequences .. autoapisummary:: pyepr.sequences.HahnEchoSequence - pyepr.sequences.T2RelaxationSequence + pyepr.sequences.HahnEchoRelaxationSequence pyepr.sequences.FieldSweepSequence pyepr.sequences.ReptimeScan pyepr.sequences.CarrPurcellSequence @@ -44,7 +45,6 @@ Pulses pyepr.pulses.Pulse pyepr.pulses.Detection - pyepr.pulses.Delay pyepr.pulses.RectPulse pyepr.pulses.GaussianPulse pyepr.pulses.HSPulse diff --git a/docsrc/README.md b/docsrc/README.md new file mode 100644 index 0000000..0b040ec --- /dev/null +++ b/docsrc/README.md @@ -0,0 +1,6 @@ + + +To build the documentation and serve it with live reloading, run: +``` +sphinx-autobuild docsrc docsrc/_build/html +``` \ No newline at end of file diff --git a/docsrc/_static/Hardware_Interface_Diagram.svg b/docsrc/_static/Hardware_Interface_Diagram.svg new file mode 100644 index 0000000..99cc327 --- /dev/null +++ b/docsrc/_static/Hardware_Interface_Diagram.svg @@ -0,0 +1,583 @@ + + + + + + + + + + + + + + + + + + + BRUKER_Interface + + + + + + + + ETH_Interface + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + XeprAPI + + + + + + Matlab + + + Engine + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Spectrometer + + + Control + + + Software + + + + + API + + + + + Interface + + + + + Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AWG + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Py + + + EPR + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docsrc/citation.rst b/docsrc/citation.rst new file mode 100644 index 0000000..1ca04dd --- /dev/null +++ b/docsrc/citation.rst @@ -0,0 +1 @@ +.. include:: ../citation.rst \ No newline at end of file diff --git a/docsrc/conf.py b/docsrc/conf.py index f70d163..f0a7cec 100644 --- a/docsrc/conf.py +++ b/docsrc/conf.py @@ -21,13 +21,16 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration extensions = ['sphinx.ext.viewcode', + 'sphinx_design', + 'myst_parser', 'sphinx.ext.intersphinx', 'autoapi.extension', 'sphinx_toolbox.collapse', 'sphinx_toolbox.code', 'sphinx_copybutton', 'numpydoc', - 'sphinx_favicon'] + 'sphinx_favicon', + 'sphinx_gallery.gen_gallery'] templates_path = ['_templates'] exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] @@ -44,6 +47,10 @@ autoapi_python_use_implicit_namespaces = True autoapi_own_page_level = 'class' +sphinx_gallery_conf = { + 'examples_dirs': 'examples', # path to your example scripts + 'gallery_dirs': 'auto_examples', # path to where to save gallery generated output +} # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output diff --git a/docsrc/dataset.rst b/docsrc/dataset.rst deleted file mode 100644 index 9306ee6..0000000 --- a/docsrc/dataset.rst +++ /dev/null @@ -1,10 +0,0 @@ -Dataset Tutorial -================ - -PyEPR uses an advanced object-oriented dataset object. This has many advantages over the traditional numpy array. - -1. **Axes**: The dataset object has named axes, which makes it easier to keep track of what each axis represents. This is especially useful when working with multidimensional data. -2. **MetaData**: The dataset object stores critical MetaData in the same object. -3. **Methods**: We are able to create EPR specific methods, allowing users to easily perform regular EPR tasks such as phase correction. - - diff --git a/docsrc/examples/GALLERY_HEADER.rst b/docsrc/examples/GALLERY_HEADER.rst new file mode 100644 index 0000000..216728d --- /dev/null +++ b/docsrc/examples/GALLERY_HEADER.rst @@ -0,0 +1,4 @@ +PyEPR Example Scripts +===================== + +Work in Progress: This gallery is under construction and will be expanded with more examples in the future. \ No newline at end of file diff --git a/docsrc/examples/config_files/BrukerElexSys_config.yaml b/docsrc/examples/config_files/BrukerElexSys_config.yaml new file mode 100644 index 0000000..d363272 --- /dev/null +++ b/docsrc/examples/config_files/BrukerElexSys_config.yaml @@ -0,0 +1,22 @@ +Spectrometer: + Type: Complete Spectrometer + Manufacturer: Bruker + Model: E580 + Local Name: Bruker E580 + + AWG: True + + + Bridge: + Min Freq: 33 #GHz + Max Freq: 35 #GHz + Digital Source: False # Analogue or Digital Source (for Q-band standalone) + d0: 650 #ns + Sample Freq: 1 # GSa/s + DutyCycle: 3 # Max amplifier duty cycle % + Pulse dt: 2 #ns + Det dt: 0.5 #ns + Det res: 8 #bit + Video BW: 125 #MHz on VAMP-III this changes the time base + On Board Pcyc: False # Use on-board phase cycling generally + On Board Pcyc (EDFS): True # Use on-board phase cycling for EDFS experiments diff --git a/docsrc/examples/config_files/Dummy_config.yaml b/docsrc/examples/config_files/Dummy_config.yaml new file mode 100644 index 0000000..962176c --- /dev/null +++ b/docsrc/examples/config_files/Dummy_config.yaml @@ -0,0 +1,20 @@ +Spectrometer: + Type: Complete Spectrometer + Manufacturer: Dummy + Model: DummyV1 + Local Name: Dummy + + AWG: True + + Bridge: + Min Freq: 33 #GHz + Max Freq: 35 #GHz + Sample Freq: 8 #GSa/s + Det Freq: 2 #GSa/s + Det Res: 12 #bit + + Dummy: + speedup: 1000 # Default: 100 + SNR: 150 + ESEEM_depth: 0.15 + noise_level: 0.005 diff --git a/docsrc/examples/config_files/ETHmatlab_config.yaml b/docsrc/examples/config_files/ETHmatlab_config.yaml new file mode 100644 index 0000000..c01ff0e --- /dev/null +++ b/docsrc/examples/config_files/ETHmatlab_config.yaml @@ -0,0 +1,16 @@ +Spectrometer: + Type: Complete Spectrometer + Manufacturer: ETH + Model: Matlab + Local Name: F243_AWG + + AWG: True + + Bridge: + Min Freq: 33 #GHz + Max Freq: 36 #GHz + Sample Freq: 8 # GSa/s + Det Freq: 2 #GSa/s + Det Res: 12 #bit + + Waveform Precision: 1 #ns diff --git a/docsrc/index.rst b/docsrc/index.rst index 46a00fe..d714c0c 100644 --- a/docsrc/index.rst +++ b/docsrc/index.rst @@ -15,16 +15,17 @@ PyEPR's Key Features - Fully python based, open-source and free to use - Intuitive object-oriented pulse sequencer -- Pre-defined common EPR experiments (CW, Hahn Echo, Inversion Recovery, Carr-Purcell, DEER, etc.) +- Pre-defined common EPR experiments (CW, Hahn Echo, Inversion Recovery, Carr-Purcell, etc.) - Easy to define custom experiments - Pre-defined common pulse shapes (rectangular, Gaussian, sech/tanh, etc.) - Easy to define custom pulse shapes - Hardware abstraction layer for interfacing with different spectrometers - BRUKER PulseSpel compiler from PyEPR sequences -.. warning:: - PyEPR is an actively developed software package, that is still very much a work in process. Please consider this to be a beta release. - +.. image:: _static/Hardware_Interface_Diagram.svg + :align: center + :width: 90% + .. toctree:: :maxdepth: 1 :hidden: @@ -39,8 +40,10 @@ PyEPR's Key Features :caption: About ./releasenotes.rst - ./contributing.rst + citation.rst + licence.rst Github autoDEER + diff --git a/docsrc/install.rst b/docsrc/install.rst index a1d9354..e431c7a 100644 --- a/docsrc/install.rst +++ b/docsrc/install.rst @@ -20,5 +20,23 @@ or with poetry: To install PyEPR from source, clone the repository and run the following command: .. code-block:: bash + + git clone https://github.com/JeschkeLab/PyEPR pip install . + +Requirements +++++++++++++ + +PyEPR requires: + - Python >= 3.11 < 3.13 + - Numpy + - Scipy + - Matplotlib + - pyyaml + - xarray + - h5netcdf + - toml + - deerlab (https://github.com/JeschkeLab/DeerLab) + - numba + - psutil diff --git a/docsrc/licence.rst b/docsrc/licence.rst new file mode 100644 index 0000000..43e1b54 --- /dev/null +++ b/docsrc/licence.rst @@ -0,0 +1,4 @@ +License +------- + +.. literalinclude:: ../LICENSE \ No newline at end of file diff --git a/docsrc/sequencer.rst b/docsrc/sequencer.rst deleted file mode 100644 index e69de29..0000000 diff --git a/docsrc/sg_execution_times.rst b/docsrc/sg_execution_times.rst new file mode 100644 index 0000000..78433a9 --- /dev/null +++ b/docsrc/sg_execution_times.rst @@ -0,0 +1,37 @@ + +:orphan: + +.. _sphx_glr_sg_execution_times: + + +Computation times +================= +**00:00.000** total execution time for 0 files **from all galleries**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - N/A + - N/A + - N/A diff --git a/docsrc/tutorial.rst b/docsrc/tutorial.rst index 7939ecb..78c5cfe 100644 --- a/docsrc/tutorial.rst +++ b/docsrc/tutorial.rst @@ -10,7 +10,7 @@ To get started, we will first import the PyEPR package. .. code-block:: python - import pyepr as esr + import pyepr as epr This will import the PyEPR package, except for the hardware modules. Importing of hardware modules is included hardware-control tutorial. @@ -18,4 +18,39 @@ Tutorial Overview ----------------- The following tutorials are available: -1. \ No newline at end of file +.. grid:: 2 + :gutter: 3 + + .. grid-item-card:: Loading and Analysing Data + :link: tutorial_loading + :link-type: doc + + Learn how to load data from the PyEPR format and other common formats, and perform basic analysis with PyEPR. + + .. grid-item-card:: Sequencer + :link: tutorial_sequencer + :link-type: doc + + Explore how to create pulse sequences, and use default sequences provided by PyEPR. + + .. grid-item-card:: Hardware Control + :link: tutorial_hardware + :link-type: doc + + Interface with physical hardware devices. + + .. grid-item-card:: Examples + :link: auto_examples/index + :link-type: doc + + View practical examples and use cases. + + +.. toctree:: + :maxdepth: 1 + :hidden: + + tutorial_loading.md + tutorial_sequencer.md + tutorial_hardware.md + auto_examples/index.rst \ No newline at end of file diff --git a/docsrc/tutorial_hardware.md b/docsrc/tutorial_hardware.md new file mode 100644 index 0000000..90abf79 --- /dev/null +++ b/docsrc/tutorial_hardware.md @@ -0,0 +1,95 @@ +# Interfacing with Hardware + +PyEPR has been designed to interface with a range of different EPR spectrometers, providing a hardware abstraction layer that allows users to write experiments in a hardware-agnostic manner. Currently, PyEPR supports the following hardware interfaces: + - Bruker ElexSys AWG based spectrometers + - ETH Zürich Matlab based homebuilt spectrometers + +For homebuilt spectrometers, there can be additional packages required. Please refer to the respective hardware interface documentation for more details. + +## Initializing Hardware Interfaces +The hardware interfaces can be initialized by importing the respective classes from the `pyepr.hardware` module and providing a configuration file that specifies the hardware settings. +```{eval-rst} +.. tab-set:: + + .. tab-item:: Bruker AWG + + .. code-block:: python + + from pyepr.hardware.Bruker_AWG import BrukerAWG + # Initialize the Bruker AWG interface with a configuration file + interface = BrukerAWG('path/to/config_file.yaml') + + .. tab-item:: ETH Matlab + + .. code-block:: python + + from pyepr.hardware.ETH_awg import ETH_awg_interface + # Initialize the ETH Matlab interface with a configuration file + interface = ETH_awg_interface('path/to/config_file.yaml') + + +``` + +### Configuration Files + +```{eval-rst} +.. tab-set:: + + .. tab-item:: Bruker AWG + + .. literalinclude:: examples/config_files/BrukerElexSys_config.yaml + :language: yaml + + + .. tab-item:: ETH Matlab + + .. literalinclude:: examples/config_files/ETHmatlab_config.yaml + :language: yaml + + .. tab-item:: Dummy + + .. literalinclude:: examples/config_files/Dummy_config.yaml + :language: yaml + +``` + +### First Tests +After initializing the hardware interface, it is recommended to run some basic tests to ensure that the connection to the spectrometer is working correctly. + + + +## Pulse Tuning + +The hardware interface can be used to create and tune pulses for the spectrometer. + +### Creating rectangular pulse pairs +Often we just need a pair of rectangular pulses. These can be quickly created though an amplitude sweep. + +```python +p90, p180 = interface.tune_rectpulse( + tp = 16, # Pulse length of pi/2 pulse in ns + B = 12200, # Magnetic field in Gauss + freq = 34.0, # Microwave frequency in GHz + reptime = 3000, # Repetition time in us + shots = 20, # Number of shots per point + ) +``` +This will create and return a pi/2 and pi rectangular pulse tuned to the specified field and frequency. The pulses can then be used directly in sequences, and have the correct scale (amplitude) set for the hardware. + +### Tuning pre-defined pulse shapes +Often a specific pulse shape is required, and it is better to tune that pulse directly. This can be done using the `tune_pulse` method of the hardware interface. +This is done as an amplitude sweep, either as a Hahn Echo (`amp_hahn`) or more commonly as a hole-buring recovery experiment (`amp_nut`). +When a hole-burning recovery experiment is used, a pair of on-resonance rectangular pulses are first created using the `tune_rectpulse` method. + +```python +from pyepr.pulses import GaussPulse +pulse = GaussPulse(tp=32, freq=0, flipangle=np.pi) # Create a Gaussian pulse with length 32 ns +tuned_pulse = interface.tune_pulse( + pulse, + 'amp_nut', + B = 12200, # Magnetic field in Gauss + freq = 34.0, # Microwave frequency in GHz + reptime = 3000, # Repetition time in us + shots = 20, # Number of shots per point + ) +``` \ No newline at end of file diff --git a/docsrc/tutorial_loading.md b/docsrc/tutorial_loading.md new file mode 100644 index 0000000..1d9f42d --- /dev/null +++ b/docsrc/tutorial_loading.md @@ -0,0 +1,93 @@ +# Loading and Analysing Data + +The PyEPR package normally saves data in the HDF5 format, which is a widely used file format for storing large amounts of numerical data. Files which are saved in this format typically have the file extension `.h5` or `.hdf5`, and if created by PyEPR will have the metadata stored in an easily accessible format for PyEPR to read. Nonetheless, PyEPR can also load data from other file formats, such as text files (`.txt`, `.csv`), Bruker Elexsys files (`.dta`, `.dsc`). + +Data is loaded into the xarray `Dataarray` object, which is a powerful data structure for handling multi-dimensional arrays with labeled axes and coordinates. This allows for easy manipulation, analysis, and visualization of the data. + +## Loading Data + +```python +import pyepr as epr +# Load data from an HDF5 file +data = epr.eprload('path/to/datafile.h5') +# Load data from a text file +data_txt = epr.eprload('path/to/datafile.txt') +``` + +## Viewing Data +Once the data is loaded, you can view its contents and metadata using standard xarray methods. + +```python +# Print the data array +print(data) +# Access metadata +print(data.attrs) +``` +The data can also be quickly visualized using the built-in plotting functions. + +```python +# Plot the data +data.real.plot(label='Re') +data.imag.plot(label='Im') +``` + +Xarray has been extended to include some convient EPR methods, such as `correctphase`. + +```python +# Correct the phase of the EPR signal +data_corrected = data.epr.correctphase() +data_corrected.plot(label='Corrected Re') +``` + +## Saving Data +After processing and analyzing the data, you can save it back to an HDF5 file for future use. +```python +# Save the processed data to an HDF5 file +data_corrected.epr.save('path/to/processed_datafile') +``` + +## PyEPR Automated Data Analysis +Since in EPR we often have to perform standard data analysis routines, PyEPR includes a set of automated data analysis functions that can be applied to the loaded data. These functions are designed to streamline the process of extracting the necessary information to move onto the next experiment. +A list of currently implemented automated data analysis functions can be found in the [API documentation](API_docs.rst). + +### Field Sweep Analysis + +```python +fieldsweep_data = epr.eprload('path/to/fieldsweep_datafile.h5') +fieldsweep = epr.FieldSweepAnalysis(fieldsweep_data) +# Determine the gyromagnetic ratio +gyro = fieldsweep.calc_gyro() +# Plot the results +fieldsweep.plot() +``` + +### Relaxation Analysis + +```{eval-rst} +.. tab-set:: + + .. tab-item:: Repetition Time T1 Recovery + + .. code-block:: python + + t1_data = epr.eprload('path/to/t1_datafile.h5') + t1_analysis = epr.ReptimeAnalysis(t1_data) + # Calculate T1 relaxation time + t1_result = t1_analysis.fit() + # Plot the results + t1_analysis.plot() + + .. tab-item:: Hahn Echo Tm Relaxation + + .. code-block:: python + + tm_data = epr.eprload('path/to/tm_datafile.h5') + t2_analysis = epr.HahnEchoRelaxationAnalysis(t2_data) + # Calculate T2 relaxation time + t2_result = t2_analysis.fit() + # Plot the results + t2_analysis.plot() + +``` + +### Resonator Profile Analysis diff --git a/docsrc/tutorial_sequencer.md b/docsrc/tutorial_sequencer.md new file mode 100644 index 0000000..a78d50c --- /dev/null +++ b/docsrc/tutorial_sequencer.md @@ -0,0 +1,103 @@ +# Pulse Sequencer + +PyEPR provides an intuitive object-oriented pulse programmer allowing the user to design pulsesequences in a hardware-agnostic manner. Additionally, several common EPR experiments are pre-defined and can be easily instantiated and modified. + +PyEPR uses ns, GHz and G as the default time, frequency and field units. Very occasionally, other units such as µs or MHz are used, in which case it will be explicitly mentioned. + +## Seqeunce Construction + +First we must import the pyepr package, and set our waveform precision. This waveform precision determines the time resolution of the pulse length and positons. If values are given that are not multiples of the waveform precision, they will be rounded. + +```python +import pyepr as epr +epr.set_waveform_precision(2) # Set waveform precision to 2 ns +``` + +Next, we want to create a sequence object. Here we are aiming to create a simple Hahn Echo sequence. +It is normally recommened, to set the field `B` and frequency `freq` as external variables. +```python +B = 12200 # Magnetic field in Gauss +freq = 34.0 # Microwave frequency in GHz +seq = epr.Sequence(name='Hahn Echo Sequence', + B = B, + freq = freq, + reptime = 3e3,# Repetition time in us + averages = 1, + shots = 20, # Number of shots per point + ) +``` +Now we need to define some pulses that can be used in our sequence. Here we create a 90 degree and a 180 degree rectangular pulse. +These pulses will eventually need a scale (amplitude), before the sequence can be run on hardware. +A Detection window is also created +```python +p90 = epr.RectPulse(tp=16, + freq=0, # Frequency offset in MHz, w.r.t the sequence frequency, + flipangle=np.pi/2, # Flip angle in degrees + pcyc = {"phases":[0, np.pi], "dets":[1,-1]} + ) +p180 = epr.RectPulse(tp=32, + freq=0, # Frequency offset in MHz, w.r.t the sequence frequency, + flipangle=np.pi, # Flip angle in degrees + ) +det = epr.Detetction(tp=32, + freq=0, # Frequency offset in MHz, w.r.t the sequence frequency, + ) +``` +We now need a time axis for our sequence and to add them to the sequence object. +When a pulse is copied into the sequence using the `add_pulse` method, parameters can be modified allowing the same pulse can be used multiple times with different timings or amplitudes. +```python +t = epr.Parameter(name='Interpulse Delay', + value=400, # Initial interpulse delay in ns + step=8, # Step size in ns + dim=1024 # Number of points, + unit='ns' # Unit of the parameter + description='Interpulse delay between the pi/2 and pi pulse' + ) + +# Adding the pulses to the sequence +seq.add_pulse(p90.copy(t=0)) +seq.add_pulse(p180.copy(t=t)) +seq.add_pulse(det.copy(t=2*t)) + +# Defining the evolution +seq.evolution([t]) +``` +### Advanced Sequences +The sequence class is capable of more advanced features such as: +- Linked axes +- Reduced axes +- Non-linear axes + +## Default Experiments +For convienience, several common EPR experiments are pre-defined and can be easily instantiated and modified. +A list of currently implemented experiments can be found in the [API documentation](API_docs.rst). +Here we show how to create a simple Hahn Echo Relaxation experiment. +```python +HE_Seq = epr.HahnEchoRelaxationSequence( + B = B, + freq = freq, + reptime = 3e3, # Repetition time in us + averages = 1, + shots = 20, # Number of shots per point + start = 400, # Initial interpulse delay in ns + step = 8, # Step size in ns + dim = 1024 # Number of points + pi2_pulse = p90, # The 90 degree pulse + pi_pulse = p180 # The 180 degree pulse +) +``` + +## Advanced Pulses +More complex pulse shapes can be created using the pulse classes provided in the `pyepr.pulses` module. A list of currently implemented pulse shapes, and their necessary inputs can be found in the [API documentation](API_docs.rst). + +Here we show how to create a simple chirp pulse +```python +from pyepr.pulses import ChirpPulse + +pulse = ChirpPulse( + tp = 128, # Pulse length in ns + init_freq = -0.1, # Frequency offset in GHz, w.r.t the sequence frequency, + final_freq = 0.1, # Frequency offset in GHz, w.r.t the sequence frequency, + flipangle = np.pi, # Flip angle in radians +) +``` diff --git a/pyepr/hardware/Bruker_AWG.py b/pyepr/hardware/Bruker_AWG.py index c6f2503..52fac3f 100644 --- a/pyepr/hardware/Bruker_AWG.py +++ b/pyepr/hardware/Bruker_AWG.py @@ -29,7 +29,7 @@ class BrukerAWG(Interface): Spectrometers. """ - def __init__(self, config_file:dict) -> None: + def __init__(self, config_file) -> None: """An interface for connecting to AWG based Bruker ELEXSYS-II Spectrometers. @@ -44,7 +44,7 @@ def __init__(self, config_file:dict) -> None: Parameters ---------- - config_file : dict + config_file : str The path to a YAML configuration file. Attributes @@ -71,7 +71,7 @@ def __init__(self, config_file:dict) -> None: self.savefolder = str(Path.home()) self.setup_flag=False - super().__init__() + super().__init__(config_file) def connect(self, d0=None) -> None: diff --git a/pyepr/sequences.py b/pyepr/sequences.py index 74cbfad..55b7f74 100644 --- a/pyepr/sequences.py +++ b/pyepr/sequences.py @@ -755,9 +755,10 @@ class T1InversionRecoverySequence(Sequence): """ # ============================================================================= -class T2RelaxationSequence(HahnEchoSequence): + +class HahnEchoRelaxationSequence(HahnEchoSequence): """ - Represents a T2 relaxation sequence. A Hahn Echo where the interpulse delay increases + Represents a Hahn Echo relaxation sequence for measureing Tm. A Hahn Echo where the interpulse delay increases Parameters ---------- @@ -805,6 +806,40 @@ def simulate(self,ESEEM_depth=0.1, Tm=1e3): data *= _gen_ESEEM(xaxis, 7.842, ESEEM_depth) return xaxis, data +class T2RelaxationSequence(HahnEchoRelaxationSequence): + """ + Represents a T2 relaxation sequence. This is an alias for HahnEchoRelaxationSequence. + A Hahn Echo where the interpulse delay increases. + + Parameters + ---------- + B : int or float + The B0 field, in Guass + freq : int or float + The freq frequency in GHz + reptime : _type_ + The shot repetition time in us + averages : int + The number of scans. + shots : int + The number of shots per point + start : float + The minimum interpulse delay in ns, by default 500 ns + step : float + The step size of the interpulse delay in ns, by default 40 ns + dim : int + The number of points in the X axis + + Optional Parameters + ------------------- + pi2_pulse : Pulse + An autoEPR Pulse object describing the excitation pi/2 pulse. If + not specified a RectPulse will be created instead. + pi_pulse : Pulse + An autoEPR Pulse object describing the refocusing pi pulses. If + not specified a RectPulse will be created instead. + """ + pass # ============================================================================= diff --git a/pyproject.toml b/pyproject.toml index 199806c..bbd42c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,10 @@ sphinx-toolbox = "^3.8.1" sphinx-copybutton = "^0.5.2" numpydoc = "^1.8.0" sphinx-favicon = "^1.0.1" +sphinx-autobuild = "^2025.8.25" +sphinx-gallery = "^0.19.0" +myst-parser = "^4.0.1" +sphinx-design = "^0.6.1" [build-system] requires = ["poetry-core"]