From 3e817be079e3d94908923dec31628b3cc7efab22 Mon Sep 17 00:00:00 2001
From: Watanyu Foosang <watanyu.f@gmail.com>
Date: Tue, 9 Mar 2021 16:32:54 +0100
Subject: [PATCH] Add action monitor and plot

- cs_invariant method in Bunch is renamed to 'action'.
- Action is now saved together with BunchMonitor and can be plotted in plot_bunchdata
---
 tracking/monitors/monitors.py | 10 +++++----
 tracking/monitors/plotting.py | 41 ++++++++++++++++++++---------------
 tracking/particles.py         |  4 ++--
 3 files changed, 32 insertions(+), 23 deletions(-)

diff --git a/tracking/monitors/monitors.py b/tracking/monitors/monitors.py
index 7a2b209..88ae258 100644
--- a/tracking/monitors/monitors.py
+++ b/tracking/monitors/monitors.py
@@ -230,7 +230,8 @@ class Monitor(Element, metaclass=ABCMeta):
             
 class BunchMonitor(Monitor):
     """
-    Monitor a single bunch and save attributes (mean, std, emit and current).
+    Monitor a single bunch and save attributes 
+    (mean, std, emit, current, and action).
     
     Parameters
     ----------
@@ -267,9 +268,11 @@ class BunchMonitor(Monitor):
         self.bunch_number = bunch_number
         group_name = "BunchData_" + str(self.bunch_number)
         dict_buffer = {"mean":(6, buffer_size), "std":(6, buffer_size),
-                     "emit":(3, buffer_size), "current":(buffer_size,)}
+                     "emit":(3, buffer_size), "current":(buffer_size,),
+                     "action":(2, buffer_size)}
         dict_file = {"mean":(6, total_size), "std":(6, total_size),
-                     "emit":(3, total_size), "current":(total_size,)}
+                     "emit":(3, total_size), "current":(total_size,),
+                     "action":(2, total_size)}
         self.monitor_init(group_name, save_every, buffer_size, total_size,
                           dict_buffer, dict_file, file_name, mpi_mode)
         
@@ -984,4 +987,3 @@ class TuneMonitor(Monitor):
         spread = np.nanstd(tune_single_particle, 0)
         
         return (mean, spread)
-    
\ No newline at end of file
diff --git a/tracking/monitors/plotting.py b/tracking/monitors/plotting.py
index 63ed6bf..bbd39ba 100644
--- a/tracking/monitors/plotting.py
+++ b/tracking/monitors/plotting.py
@@ -112,7 +112,7 @@ def plot_beamdata(filename, dataset, option=None, stat_var=None, x_var="time"):
     file.close()
     return fig    
               
-def plot_bunchdata(filename, bunch_number, dataset, option=None, x_var="time"):
+def plot_bunchdata(filename, bunch_number, dataset, dimension="x", x_var="time"):
     """
     Plot data recorded by BunchMonitor.
     
@@ -123,13 +123,14 @@ def plot_bunchdata(filename, bunch_number, dataset, option=None, x_var="time"):
     bunch_number : int
         Bunch to plot. This has to be identical to 'bunch_number' parameter in 
         'BunchMonitor' object.
-    detaset : {"current","emit","mean","std"}
+    dataset : {"current", "emit", "mean", "std", "action"}
         HDF5 file's dataset to be plotted.
-    option : str, optional
-        If dataset is "emit", "mean", or "std", the variable name to be plotted
-        needs to be specified :
-            for "emit", option = {"x","y","s"}
-            for "mean" and "std", option = {"x","xp","y","yp","tau","delta"}    
+    dimension : str, optional
+        The dimension of the dataset to plot. Use "None" for "current",
+        otherwise use the following : 
+            for "emit", dimension = {"x","y","s"},
+            for "mean" and "std", dimension = {"x","xp","y","yp","tau","delta"},
+            for "action", dimension = {"x","y"}.
     x_var : {"time", "current"}, optional
         Variable to be plotted on the horizontal axis. The default is "time".
         
@@ -149,19 +150,19 @@ def plot_bunchdata(filename, bunch_number, dataset, option=None, x_var="time"):
         label = "current (mA)"
         
     elif dataset == "emit":
-        option_dict = {"x":0, "y":1, "s":2}
+        dimension_dict = {"x":0, "y":1, "s":2}
                          
-        y_var = file[group][dataset][option_dict[option]]*1e9
+        y_var = file[group][dataset][dimension_dict[dimension]]*1e9
         
-        if option == "x": label = "hor. emittance (nm.rad)"
-        elif option == "y": label = "ver. emittance (nm.rad)"
-        elif option == "s": label = "long. emittance (nm.rad)"
+        if dimension == "x": label = "hor. emittance (nm.rad)"
+        elif dimension == "y": label = "ver. emittance (nm.rad)"
+        elif dimension == "s": label = "long. emittance (nm.rad)"
         
         
-    elif dataset == "mean" or "std":                        
-        option_dict = {"x":0, "xp":1, "y":2, "yp":3, "tau":4, "delta":5} 
+    elif dataset == "mean" or dataset == "std":                        
+        dimension_dict = {"x":0, "xp":1, "y":2, "yp":3, "tau":4, "delta":5} 
         scale = [1e6, 1e6, 1e6, 1e6, 1e12, 1]        
-        axis_index = option_dict[option]
+        axis_index = dimension_dict[dimension]
         
         y_var = file[group][dataset][axis_index]*scale[axis_index]
         if dataset == "mean":
@@ -174,6 +175,13 @@ def plot_bunchdata(filename, bunch_number, dataset, option=None, x_var="time"):
         
         label = label_list[axis_index]
         
+    elif dataset == "action":
+        dimension_dict = {"x":0, "y":1}
+        axis_index = dimension_dict[dimension]
+        y_var = file[group][dataset][axis_index]
+        label_list = ['$J_x$ (m)', '$J_y$ (m)']
+        label = label_list[axis_index]
+        
     if x_var == "current":
         x_axis = file[group]["current"][:] * 1e3
         xlabel = "current (mA)"
@@ -544,5 +552,4 @@ def plot_tunedata(filename, bunch_number):
     ax2.set_ylabel("Synchrotron tune")
     
     file.close()
-    return (fig1, fig2)
-    
\ No newline at end of file
+    return (fig1, fig2)  
\ No newline at end of file
diff --git a/tracking/particles.py b/tracking/particles.py
index c272e98..c9ad596 100644
--- a/tracking/particles.py
+++ b/tracking/particles.py
@@ -232,9 +232,9 @@ class Bunch:
         return np.array([emitX, emitY, emitS])
     
     @property
-    def cs_invariant(self):
+    def action(self):
         """
-        Return the average Couran-Snyder invariant of each plane.
+        Return the average action (Couran-Snyder invariant) of each plane.
 
         """
         Jx = (self.ring.optics.local_gamma[0] * self['x']**2) + \
-- 
GitLab