From 36c68fc45f4a6c97d6ef9513c480d1c23c3f968f Mon Sep 17 00:00:00 2001 From: Philipp Niedermayer <p.niedermayer@gsi.de> Date: Tue, 31 May 2022 13:14:59 +0200 Subject: [PATCH] Documentation --- README.md | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++ data.py | 10 +++++++--- plotting.py | 43 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 99 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 44576cc..f632901 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,61 @@ git submodule init git -c http.sslVerify=false submodule update bdiolib ``` +### Examples +**Tip**: In jupyter notbooks press SHIFT+TAB to show method signature and docstrings + +- https://git.gsi.de/p.niedermayer/data-analysis-2022-05-06-exciter/-/blob/main/analysis.ipynb +- https://git.gsi.de/p.niedermayer/data-analysis-2022-05-08-btf/-/blob/main/analysis.ipynb + + +```python +from analysis_utils.data import * +from analysis_utils.fitting import * +from analysis_utils.plotting import * + +fig, ax = plt.subplots(constrained_layout=True) + +# Libera bunch-by-bunch data +data = LiberaBBBData.from_file('libera_ireg_dump.bin').to_tbt_data(h=2) +plot_tbt(ax, data, 'fxys', + turn_range=(0, 1900000), + over_time=True, +) +plot_tune_spectrogram(ax, data, 'x', + over_time=True, +) +plot_tune_spectrum(ax, data, 'x', + tune_range=(0.315,0.335) + smoothing=500, + fit=fit_lorenzian, +) + + +# Data from old SIS18 IPM +data = IPMData.from_file(d['ipm'], + from_event=EVT_MB_TRIGGER, +) +ax.imshow(data.x.T, extent=(data.t[0], data.t[-1], data.w[-1], data.w[0]), + aspect='auto', rasterized=True, cmap='gist_heat_r', vmin=0, vmax=100 +) +plot_beam_size(ax, data, 'x', + time_range=(2, 4), + smoothing=10 +) + + +# Data from SIS18 BTF Network analyser +data = NWAData.from_file('magnitude.csv', 'phase.csv'], + isdeg=True, unwrap=True) +data.m_unit = 'dB' +plot_btf(ax1, ax2, data, + frev=854e3 +) + + + +``` diff --git a/data.py b/data.py index 471d974..851e406 100644 --- a/data.py +++ b/data.py @@ -54,7 +54,8 @@ class LassieSpillData(Trace): """Read in time series data from a *.tdf file saved with lassiespill or DCCT application :param fname: path to filename - :param from_event: return data from this event, time will also be relative to this event + :param from_event: return data from this event, time will also be relative to this event + :param time_offset: adds a given time offset (in s) to the timestamps References: https://git.acc.gsi.de/bi/bdiolib.python """ @@ -170,8 +171,9 @@ class IPMData(Trace): :param fname: path to filename :param clean: if True, use calibrated data from adc_clean.dat instead of raw data from adc.dat - :param from_event: return data from this event on, time will also be relative to this event :param subtract_background: if True, subtract background level prior to injection + :param from_event: return data from this event on, time will also be relative to this event + :param time_offset: adds a given time offset (in s) to the timestamps References: Giacomini, Tino <T.Giacomini@gsi.de> @@ -291,6 +293,8 @@ class LiberaBBBData(LiberaData): """Read in bunch-by-bunch data from a *.bin file saved with libera-ireg :param fname: path to filename + :param time_offset: adds a given time offset (in s) to the timestamps + References: Libera_Hadron_User_Manual_1.04.pdf """ bunch = np.memmap(fname, dtype=np.dtype([ @@ -341,7 +345,7 @@ class NWAData(Trace): def from_file(cls, magfile, phasefile=None, *, isdeg=True, unwrap=False, verbose=0): """Read in data from CSV file for magnitude and phase - :param magfile: path to filename with magnitude trace data + :param magfile: path to filename with magnitude trace data (and optional phase data, see phasefile) :param phasefile: path to filename with phase trace data. If None, phase data is assumed to be the second column in magfile. :param unwrap: if true, relative phase is unwraped to absolute phase centered around zero :param isdeg: if phase data is in degree (True) or radians (False) diff --git a/plotting.py b/plotting.py index e4dd012..d404abd 100644 --- a/plotting.py +++ b/plotting.py @@ -64,7 +64,7 @@ def add_resonance_vlines(axes, max_order, color='r'): alpha=1/max(1, m-2), text_vertical=True, text_top=True) def subplot_shared_labels(axes, xlabel=None, ylabel=None, clear='auto'): - """Adds labels to shared axes as needed + """Adds and removes labels to shared axes as needed :param axes: 2D array of axes from subplots (pass squeeze=False to plt.subplots if required) :param xlabel: the shared xlabel @@ -88,6 +88,11 @@ def subplot_shared_labels(axes, xlabel=None, ylabel=None, clear='auto'): axes[r,c].set(ylabel=ylabel) def grid_diagonal(ax, **kwargs): + """Adds a diagonal grid to the given axes + + :param ax: the axes + :param kwargs: optional arguments passed to ax.axline + """ for k, v in dict(color='lightgray',lw=1,zorder=-100).items(): kwargs.setdefault(k, v) xlim, ylim = ax.get_xlim(), ax.get_ylim() @@ -102,8 +107,14 @@ def grid_diagonal(ax, **kwargs): def fiberplot(ax, datasets, *, labels=[None, None], vertical=True): - """Create a - :param datasets: 2D array of datasets (position, x, y) or dict with two levels + """Create a fiberplot with multiple datasets of x and y data + x is plotted on the horizontal (vertical) axis + y determines the height (width) of the fiberplot + position of each dataset determines the fiberplot position on the vertical (horizontal) axis + label can be used to compare 2 categories where the fiberplot is split into two + + :param datasets: 2D array of datasets [(position, x, y), ...] or dict with two levels {label: {position: (x,y), ...}, ...} + """ if type(datasets) is dict: labels = list(datasets.keys()) @@ -163,7 +174,11 @@ def turn_or_time_range(time, turn_range=None, time_range=None): def plot_tbt(ax, libera_data, what='fsxy', *, over_time=True, turn_range=None, time_range=None): """Plot turn-by-turn data - :param what: list of signals to plot: f, s, x, y + :param libera_data: instance of LiberaTBTData + :param what: signals to plot, any combination of 'f' (revolution frequency), 's' (sum signal), 'x' and/or 'y' (position) + :param over_time: if True, plot data as function of time rather than turn + :param turn_range: (start, stop) tuple of turns to plot + :param time_range: (start, stop) tuple of time in s to plot """ assert isinstance(libera_data, LiberaTBTData), f'Expected LiberaTBTData but got {type(libera_data)}' @@ -196,6 +211,14 @@ def plot_tbt(ax, libera_data, what='fsxy', *, over_time=True, turn_range=None, t def plot_btf(axf, axp, data, *, frev=None, **kwargs): + """Plot beam transfer function + + :param axf: axis for magnitude response + :param axp: axis for phase response + :param data: instance of NWAData + :param frev: if not None, plot fraction of revolution frequency (tune) on x axis + :param kwargs: arguments passed to plot function + """ f = data.f*(1/frev if frev else 1) axf.plot(f, data.m, **kwargs) @@ -212,7 +235,10 @@ def plot_tune_spectrum(ax, libera_data, xy, turn_range=None, time_range=None, tu :param libera_data: Instance of LiberaTBTData class :param xy: either 'x' or 'y' :param turn_range: tuple of (start_turn, stop_turn) for range to plot - :param turn_range: tuple of (start_time, stop_time) in seconds for range to plot + :param time_range: tuple of (start_time, stop_time) in seconds for range to plot + :param tune_range: tuple of (start_tune, stop_tune) for range to plot + :param fit: if True or any of (fit_lorenzian, fit_gaussian), determine the tune from a fit on the spectrum + :param smoothing: if specified, apply a moving average smoothing filter of this width to the data """ assert isinstance(libera_data, LiberaTBTData), f'Expected LiberaTBTData but got {type(libera_data)}' @@ -417,6 +443,13 @@ def plot_tune_spectrogram(ax, libera_data, xy, *, nperseg=2**12, noverlap=None, ########### def plot_beam_size(ax, ipm_data, xy, time_range=None, smoothing=None, **kwargs): + """Plot beam size as function of time from fitted IPM data + + :param ipm_data: instance of IPMData + :param xy: plane to consider, either 'x' or 'y' + :param time_range: range of (start, stop) time in s to plot + :param smoothing: if specified, apply a moving average smoothing filter of this width to the data + """ mask = irng(ipm_data.t, *time_range) data = getattr(ipm_data, xy)[mask] -- GitLab