From 19b8fdab005123248ce7c98b0d97e1a9a20bc3c4 Mon Sep 17 00:00:00 2001 From: Thomas Morris Date: Mon, 17 Jul 2023 11:30:46 -0400 Subject: [PATCH 1/5] convert integer sirepo parameters to floats --- sirepo_bluesky/sirepo_ophyd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sirepo_bluesky/sirepo_ophyd.py b/sirepo_bluesky/sirepo_ophyd.py index 1df3874f..8f1c5acb 100644 --- a/sirepo_bluesky/sirepo_ophyd.py +++ b/sirepo_bluesky/sirepo_ophyd.py @@ -401,7 +401,7 @@ def create_classes(sirepo_data, connection, create_objects=True, extra_model_fie components[k] = Cpt( cpt_class, - value=v, + value=(float(v) if type(v) is int else v), sirepo_dict=sirepo_dict, sirepo_param=k, ) From 5d2634b025c3796e235ae45e83ed63b7e7114b15 Mon Sep 17 00:00:00 2001 From: Thomas Morris Date: Mon, 17 Jul 2023 12:10:02 -0400 Subject: [PATCH 2/5] suppress shadow stdout --- sirepo_bluesky/shadow_handler.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sirepo_bluesky/shadow_handler.py b/sirepo_bluesky/shadow_handler.py index fa902efe..3ff1fc44 100644 --- a/sirepo_bluesky/shadow_handler.py +++ b/sirepo_bluesky/shadow_handler.py @@ -1,3 +1,6 @@ +import contextlib +import os + import numpy as np import Shadow.ShadowLibExtensions as sd import Shadow.ShadowTools @@ -49,7 +52,9 @@ def read_shadow_file_col(filename, parameter=30): 32 S2-stokes = 2 |Es| |Ep| cos(phase_s-phase_p) 33 S3-stokes = 2 |Es| |Ep| sin(phase_s-phase_p) """ - data = Shadow.ShadowTools.getshcol(filename, col=parameter) + with open(os.devnull, "w") as devnull: + with contextlib.redirect_stdout(devnull): + data = Shadow.ShadowTools.getshcol(filename, col=parameter) mean_value = np.mean(data) @@ -73,7 +78,9 @@ def read_shadow_file(filename, histogram_bins=None): beam.load(filename) # 1=X spatial coordinate; 3=Z spatial coordinate - data_dict = beam.histo2(1, 3, nolost=1, nbins=histogram_bins) + with open(os.devnull, "w") as devnull: + with contextlib.redirect_stdout(devnull): + data_dict = beam.histo2(1, 3, nolost=1, nbins=histogram_bins) data = data_dict["histogram"] # This returns a list of N values (N=number of rays) From 8062893a6ecebb4298d723c1b8eb116e6312d4ec Mon Sep 17 00:00:00 2001 From: Thomas Morris Date: Mon, 17 Jul 2023 12:11:22 -0400 Subject: [PATCH 3/5] suppress shadow stdout --- sirepo_bluesky/shadow_handler.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sirepo_bluesky/shadow_handler.py b/sirepo_bluesky/shadow_handler.py index 3ff1fc44..a906dde6 100644 --- a/sirepo_bluesky/shadow_handler.py +++ b/sirepo_bluesky/shadow_handler.py @@ -81,11 +81,11 @@ def read_shadow_file(filename, histogram_bins=None): with open(os.devnull, "w") as devnull: with contextlib.redirect_stdout(devnull): data_dict = beam.histo2(1, 3, nolost=1, nbins=histogram_bins) - data = data_dict["histogram"] + data = data_dict["histogram"] - # This returns a list of N values (N=number of rays) - photon_energy_list = Shadow.ShadowTools.getshcol(filename, col=11) # 11=Energy [eV] - photon_energy = np.mean(photon_energy_list) + # This returns a list of N values (N=number of rays) + photon_energy_list = Shadow.ShadowTools.getshcol(filename, col=11) # 11=Energy [eV] + photon_energy = np.mean(photon_energy_list) return { "data": data, From 6373fc5260c4db25d0e1ae12daaed34aca2e95bb Mon Sep 17 00:00:00 2001 From: Thomas Morris Date: Mon, 17 Jul 2023 13:51:57 -0400 Subject: [PATCH 4/5] added lightweight beam statistics function for images --- sirepo_bluesky/shadow_handler.py | 27 +++++++++++++++++++-------- sirepo_bluesky/sirepo_ophyd.py | 17 ++++++++++++++++- sirepo_bluesky/srw_handler.py | 24 ++++++++++++++++++------ sirepo_bluesky/utils/__init__.py | 27 +++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 15 deletions(-) diff --git a/sirepo_bluesky/shadow_handler.py b/sirepo_bluesky/shadow_handler.py index a906dde6..b169a177 100644 --- a/sirepo_bluesky/shadow_handler.py +++ b/sirepo_bluesky/shadow_handler.py @@ -5,6 +5,8 @@ import Shadow.ShadowLibExtensions as sd import Shadow.ShadowTools +from . import utils + def read_shadow_file_col(filename, parameter=30): """Read specified parameter from the Shadow3 output binary file. @@ -81,23 +83,32 @@ def read_shadow_file(filename, histogram_bins=None): with open(os.devnull, "w") as devnull: with contextlib.redirect_stdout(devnull): data_dict = beam.histo2(1, 3, nolost=1, nbins=histogram_bins) - data = data_dict["histogram"] # This returns a list of N values (N=number of rays) photon_energy_list = Shadow.ShadowTools.getshcol(filename, col=11) # 11=Energy [eV] - photon_energy = np.mean(photon_energy_list) - return { + data = data_dict["histogram"] + photon_energy = np.mean(photon_energy_list) + + # convert to um + horizontal_extent = 1e3 * np.array(data_dict["xrange"][:2]) + vertical_extent = 1e3 * np.array(data_dict["yrange"][:2]) + + ret = { "data": data, "shape": data.shape, - "mean": np.mean(data), + "flux": data.sum(), + "mean": data.mean(), "photon_energy": photon_energy, - "horizontal_extent": data_dict["xrange"][:2], - "vertical_extent": data_dict["yrange"][:2], - # 'labels': labels, - # 'units': units, + "horizontal_extent": horizontal_extent, + "vertical_extent": vertical_extent, + "units": "um", } + ret.update(utils.get_beam_stats(data, horizontal_extent, vertical_extent)) + + return ret + class ShadowFileHandler: specs = {"shadow"} diff --git a/sirepo_bluesky/sirepo_ophyd.py b/sirepo_bluesky/sirepo_ophyd.py index 8f1c5acb..abccdadb 100644 --- a/sirepo_bluesky/sirepo_ophyd.py +++ b/sirepo_bluesky/sirepo_ophyd.py @@ -77,7 +77,12 @@ def trigger(self, *args, **kwargs): class SirepoWatchpoint(DeviceWithJSONData): image = Cpt(ExternalFileReference, kind="normal") shape = Cpt(Signal) - mean = Cpt(Signal, kind="hinted") + flux = Cpt(Signal, kind="hinted") + mean = Cpt(Signal, kind="normal") + x = Cpt(Signal, kind="normal") + y = Cpt(Signal, kind="normal") + fwhm_x = Cpt(Signal, kind="hinted") + fwhm_y = Cpt(Signal, kind="hinted") photon_energy = Cpt(Signal, kind="normal") horizontal_extent = Cpt(Signal) vertical_extent = Cpt(Signal) @@ -152,7 +157,12 @@ def trigger(self, *args, **kwargs): def update_components(_data): self.shape.put(_data["shape"]) + self.flux.put(_data["flux"]) self.mean.put(_data["mean"]) + self.x.put(_data["x"]) + self.y.put(_data["y"]) + self.fwhm_x.put(_data["fwhm_x"]) + self.fwhm_y.put(_data["fwhm_y"]) self.photon_energy.put(_data["photon_energy"]) self.horizontal_extent.put(_data["horizontal_extent"]) self.vertical_extent.put(_data["vertical_extent"]) @@ -233,7 +243,12 @@ def trigger(self, *args, **kwargs): def update_components(_data): self.shape.put(_data["shape"]) + self.flux.put(_data["flux"]) self.mean.put(_data["mean"]) + self.x.put(_data["x"]) + self.y.put(_data["y"]) + self.fwhm_x.put(_data["fwhm_x"]) + self.fwhm_y.put(_data["fwhm_y"]) self.photon_energy.put(_data["photon_energy"]) self.horizontal_extent.put(_data["horizontal_extent"]) self.vertical_extent.put(_data["vertical_extent"]) diff --git a/sirepo_bluesky/srw_handler.py b/sirepo_bluesky/srw_handler.py index 7349fdd2..2b0dcbd5 100644 --- a/sirepo_bluesky/srw_handler.py +++ b/sirepo_bluesky/srw_handler.py @@ -1,6 +1,8 @@ import numpy as np import srwpy.uti_plot_com as srw_io +from . import utils + def read_srw_file(filename, ndim=2): data, mode, ranges, labels, units = srw_io.file_load(filename) @@ -13,18 +15,28 @@ def read_srw_file(filename, ndim=2): else: raise ValueError(f"The value ndim={ndim} is not supported.") - return { + horizontal_extent = np.array(ranges[3:5]) + vertical_extent = np.array(ranges[6:8]) + + ret = { "data": data, "shape": data.shape, - "mean": np.mean(data), + "flux": data.sum(), + "mean": data.mean(), "photon_energy": photon_energy, - "horizontal_extent": ranges[3:5], - "vertical_extent": ranges[6:8], - # 'mode': mode, + "horizontal_extent": horizontal_extent, + "vertical_extent": vertical_extent, "labels": labels, - "units": units, + "units": "units", } + if ndim == 1: + ret.update({key: np.nan for key in ["x", "y", "fwhm_x", "fwhm_y"]}) + if ndim == 2: + ret.update(utils.get_beam_stats(data, horizontal_extent, vertical_extent)) + + return ret + class SRWFileHandler: specs = {"srw"} diff --git a/sirepo_bluesky/utils/__init__.py b/sirepo_bluesky/utils/__init__.py index e69de29b..d87fb1ce 100644 --- a/sirepo_bluesky/utils/__init__.py +++ b/sirepo_bluesky/utils/__init__.py @@ -0,0 +1,27 @@ +import numpy as np + + +def get_beam_stats(image, x_extent, y_extent): + n_y, n_x = image.shape + + if image.sum() > 0: + X, Y = np.meshgrid(np.linspace(*x_extent, n_x), np.linspace(*y_extent, n_y)) + + mean_x = np.sum(X * image) / np.sum(image) + mean_y = np.sum(Y * image) / np.sum(image) + + sigma_x = np.sqrt(np.sum((X - mean_x) ** 2 * image) / np.sum(image)) + sigma_y = np.sqrt(np.sum((Y - mean_y) ** 2 * image) / np.sum(image)) + + else: + mean_x, mean_y, sigma_x, sigma_y = np.nan, np.nan, np.nan, np.nan + + return { + "shape": (n_y, n_x), + "flux": image.sum(), + "mean": image.mean(), + "x": mean_x, + "y": mean_y, + "fwhm_x": 2 * np.sqrt(2 * np.log(2)) * sigma_x, + "fwhm_y": 2 * np.sqrt(2 * np.log(2)) * sigma_y, + } From e2bda10def9d653cc83d93c4333834bcc4749e13 Mon Sep 17 00:00:00 2001 From: Thomas Morris Date: Tue, 18 Jul 2023 13:09:45 -0400 Subject: [PATCH 5/5] requested changes --- sirepo_bluesky/srw_handler.py | 2 +- sirepo_bluesky/utils/__init__.py | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/sirepo_bluesky/srw_handler.py b/sirepo_bluesky/srw_handler.py index 2b0dcbd5..6d0563a2 100644 --- a/sirepo_bluesky/srw_handler.py +++ b/sirepo_bluesky/srw_handler.py @@ -27,7 +27,7 @@ def read_srw_file(filename, ndim=2): "horizontal_extent": horizontal_extent, "vertical_extent": vertical_extent, "labels": labels, - "units": "units", + "units": units, } if ndim == 1: diff --git a/sirepo_bluesky/utils/__init__.py b/sirepo_bluesky/utils/__init__.py index d87fb1ce..ae11ce44 100644 --- a/sirepo_bluesky/utils/__init__.py +++ b/sirepo_bluesky/utils/__init__.py @@ -1,27 +1,30 @@ import numpy as np +sigma_to_fwhm = 2 * np.sqrt(2 * np.log(2)) + def get_beam_stats(image, x_extent, y_extent): n_y, n_x = image.shape + image_sum = image.sum() if image.sum() > 0: X, Y = np.meshgrid(np.linspace(*x_extent, n_x), np.linspace(*y_extent, n_y)) - mean_x = np.sum(X * image) / np.sum(image) - mean_y = np.sum(Y * image) / np.sum(image) + mean_x = np.sum(X * image) / image_sum + mean_y = np.sum(Y * image) / image_sum - sigma_x = np.sqrt(np.sum((X - mean_x) ** 2 * image) / np.sum(image)) - sigma_y = np.sqrt(np.sum((Y - mean_y) ** 2 * image) / np.sum(image)) + sigma_x = np.sqrt(np.sum((X - mean_x) ** 2 * image) / image_sum) + sigma_y = np.sqrt(np.sum((Y - mean_y) ** 2 * image) / image_sum) else: mean_x, mean_y, sigma_x, sigma_y = np.nan, np.nan, np.nan, np.nan return { "shape": (n_y, n_x), - "flux": image.sum(), + "flux": image_sum, "mean": image.mean(), "x": mean_x, "y": mean_y, - "fwhm_x": 2 * np.sqrt(2 * np.log(2)) * sigma_x, - "fwhm_y": 2 * np.sqrt(2 * np.log(2)) * sigma_y, + "fwhm_x": sigma_to_fwhm * sigma_x, + "fwhm_y": sigma_to_fwhm * sigma_y, }