From 92be75554a1b511060dc06c59b63d2bb5208f057 Mon Sep 17 00:00:00 2001 From: Alexis Gamelin <alexis.gamelin@synchrotron-soleil.fr> Date: Fri, 29 Mar 2024 15:25:19 +0100 Subject: [PATCH] Add sweep and coherent monitors of higher order --- mbtrack2/tracking/__init__.py | 1 + mbtrack2/tracking/monitors/monitors.py | 28 +++++++++++++++++ mbtrack2/tracking/particles.py | 20 +++++++++++- mbtrack2/tracking/sweep.py | 42 ++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 mbtrack2/tracking/sweep.py diff --git a/mbtrack2/tracking/__init__.py b/mbtrack2/tracking/__init__.py index 02843e2..a4ea3ff 100644 --- a/mbtrack2/tracking/__init__.py +++ b/mbtrack2/tracking/__init__.py @@ -31,3 +31,4 @@ from mbtrack2.tracking.wakepotential import ( LongRangeResistiveWall, WakePotential, ) +from mbtrack2.tracking.sweep import Sweep \ No newline at end of file diff --git a/mbtrack2/tracking/monitors/monitors.py b/mbtrack2/tracking/monitors/monitors.py index 151fe2a..f5abcbb 100644 --- a/mbtrack2/tracking/monitors/monitors.py +++ b/mbtrack2/tracking/monitors/monitors.py @@ -1083,12 +1083,18 @@ class BunchSpectrumMonitor(Monitor): dict_buffer = { "incoherent": (3, self.n_fft // 2 + 1, buffer_size), "coherent": (3, self.n_fft // 2 + 1, buffer_size), + "coherent_q":(3, self.n_fft//2+1, buffer_size), + "coherent_s":(3, self.n_fft//2+1, buffer_size), + "coherent_o":(3, self.n_fft//2+1, buffer_size), "mean_incoherent": (3, buffer_size), "std_incoherent": (3, buffer_size) } dict_file = { "incoherent": (3, self.n_fft // 2 + 1, total_size), "coherent": (3, self.n_fft // 2 + 1, total_size), + "coherent_q":(3, self.n_fft//2+1, total_size), + "coherent_s":(3, self.n_fft//2+1, total_size), + "coherent_o":(3, self.n_fft//2+1, total_size), "mean_incoherent": (3, total_size), "std_incoherent": (3, total_size) } @@ -1104,6 +1110,9 @@ class BunchSpectrumMonitor(Monitor): self.positions = np.zeros( (self.size_list, self.sample_size, self.save_every + 1)) self.mean = np.zeros((self.size_list, self.save_every + 1)) + self.std = np.zeros((self.size_list, self.save_every+1)) + self.skew = np.zeros((self.size_list, self.save_every+1)) + self.kurtosis = np.zeros((self.size_list, self.save_every+1)) index = np.arange(0, int(mp_number)) self.index_sample = sorted(random.sample(list(index), @@ -1111,6 +1120,9 @@ class BunchSpectrumMonitor(Monitor): self.incoherent = np.zeros((3, self.n_fft // 2 + 1, self.buffer_size)) self.coherent = np.zeros((3, self.n_fft // 2 + 1, self.buffer_size)) + self.coherent_q = np.zeros((3, self.n_fft//2+1, self.buffer_size)) + self.coherent_s = np.zeros((3, self.n_fft//2+1, self.buffer_size)) + self.coherent_o = np.zeros((3, self.n_fft//2+1, self.buffer_size)) self.file[self.group_name].create_dataset("freq", data=self.frequency_samples) @@ -1172,6 +1184,9 @@ class BunchSpectrumMonitor(Monitor): self.positions[value, :, self.save_count] = np.nan self.mean[:, self.save_count] = bunch.mean[self.mean_index] + self.std[:, self.save_count] = bunch.std[self.mean_index] + self.skew[:, self.save_count] = bunch.skew[self.mean_index] + self.kurtosis[:, self.save_count] = bunch.kurtosis[self.mean_index] self.save_count += 1 @@ -1201,6 +1216,10 @@ class BunchSpectrumMonitor(Monitor): self.coherent[self.store_dict[key], :, self.buffer_count] = self.get_coherent_spectrum( self.mean[value]) + self.coherent_q[self.store_dict[key],:,self.buffer_count] = self.get_coherent_spectrum(self.std[value]) + self.coherent_s[self.store_dict[key],:,self.buffer_count] = self.get_coherent_spectrum(self.skew[value]) + self.coherent_o[self.store_dict[key],:,self.buffer_count] = self.get_coherent_spectrum(self.kurtosis[value]) + self.buffer_count += 1 @@ -1236,6 +1255,15 @@ class BunchSpectrumMonitor(Monitor): self.buffer_size:(self.write_count + 1) * self.buffer_size] = self.coherent + self.file[self.group_name]["coherent_q"][:,:, + self.write_count * self.buffer_size:(self.write_count+1) * + self.buffer_size] = self.coherent_q + self.file[self.group_name]["coherent_s"][:,:, + self.write_count * self.buffer_size:(self.write_count+1) * + self.buffer_size] = self.coherent_s + self.file[self.group_name]["coherent_o"][:,:, + self.write_count * self.buffer_size:(self.write_count+1) * + self.buffer_size] = self.coherent_o self.file.flush() self.write_count += 1 diff --git a/mbtrack2/tracking/particles.py b/mbtrack2/tracking/particles.py index 7ba97ff..bff2263 100644 --- a/mbtrack2/tracking/particles.py +++ b/mbtrack2/tracking/particles.py @@ -9,7 +9,7 @@ import numpy as np import pandas as pd import seaborn as sns from scipy.constants import c, e, m_e, m_p - +from scipy.stats import moment class Particle: """ @@ -244,6 +244,24 @@ class Bunch: """ std = [[self[name].std()] for name in self] return np.squeeze(np.array(std)) + + @property + def skew(self): + """ + Return the standard deviation of the position of alive + particles for each coordinates. + """ + skew = [[moment(self[name],3)] for name in self] + return np.squeeze(np.array(skew)) + + @property + def kurtosis(self): + """ + Return the standard deviation of the position of alive + particles for each coordinates. + """ + kurtosis = [[moment(self[name],4)] for name in self] + return np.squeeze(np.array(kurtosis)) @property def emit(self): diff --git a/mbtrack2/tracking/sweep.py b/mbtrack2/tracking/sweep.py new file mode 100644 index 0000000..61d0c3d --- /dev/null +++ b/mbtrack2/tracking/sweep.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Fri Mar 29 15:12:28 2024 + +@author: gamelina +""" +import numpy as np +import matplotlib.pyplot as plt +from mbtrack2.tracking.element import Element +from scipy.signal import chirp + +class Sweep(Element): + def __init__(self, ring, f0, f1, t1, level): + self.ring = ring + self.t = np.arange(0, t1, ring.T0) + self.N = len(self.t) + self.count = 0 + self.level = level + self.sweep = chirp(self.t, f0, t1, f1) + + @Element.parallel + def track(self, bunch): + """ + Tracking method for the element. + No bunch to bunch interaction, so written for Bunch objects and + @Element.parallel is used to handle Beam objects. + + Parameters + ---------- + bunch : Bunch or Beam object + """ + sweep_val = self.sweep[self.count] + bunch["delta"] += self.level / self.ring.E0 * sweep_val + self.count += 1 + if self.count >= self.N: + self.count = 0 + + def plot(self): + fig, ax = plt.subplots() + ax.plot(self.t, self.sweep) + return fig \ No newline at end of file -- GitLab