From fa018d56012ffdb685e93200c70f81c6fd52fd19 Mon Sep 17 00:00:00 2001
From: midonc <midonc@exflong10.desy.de>
Date: Wed, 17 Apr 2024 15:32:22 +0200
Subject: [PATCH] added photonizer and xpcs code from online cluster

---
 photonizer/setup.py                     |  29 +++++
 photonizer/src/_version.py              |   4 +
 photonizer/src/photonizer/photonizer.py |  39 +++++++
 xpcs/setup.py                           |  31 ++++++
 xpcs/src/_version.py                    |   4 +
 xpcs/src/xpcs/xpcs.py                   | 139 ++++++++++++++++++++++++
 6 files changed, 246 insertions(+)
 create mode 100644 photonizer/setup.py
 create mode 100644 photonizer/src/_version.py
 create mode 100644 photonizer/src/photonizer/photonizer.py
 create mode 100644 xpcs/setup.py
 create mode 100644 xpcs/src/_version.py
 create mode 100644 xpcs/src/xpcs/xpcs.py

diff --git a/photonizer/setup.py b/photonizer/setup.py
new file mode 100644
index 0000000..f543877
--- /dev/null
+++ b/photonizer/setup.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+from os.path import dirname, join, realpath
+from setuptools import setup, find_packages, Extension
+
+from karabo.packaging.versioning import device_scm_version
+
+
+ROOT_FOLDER = dirname(realpath(__file__))
+scm_version = device_scm_version(ROOT_FOLDER, join(ROOT_FOLDER, "src", "_version.py"))
+
+
+setup(
+    name="photonizer",
+    use_scm_version=scm_version,
+    author="James Wrigley",
+    author_email="da-support@xfel.eu",
+    description="",
+    long_description="",
+    url="",
+    package_dir={"": "src"},
+    packages=find_packages("src"),
+    entry_points={
+        "calng.correction_addon": [
+            "Photonizer = photonizer.photonizer:Photonizer",
+        ],
+    },
+    requires=[],
+)
diff --git a/photonizer/src/_version.py b/photonizer/src/_version.py
new file mode 100644
index 0000000..0731bb7
--- /dev/null
+++ b/photonizer/src/_version.py
@@ -0,0 +1,4 @@
+# coding: utf-8
+# file generated by setuptools_scm
+# don't change, don't track in version control
+version = '0.0.1-2.17.0-0-g250da4f-dirty'
diff --git a/photonizer/src/photonizer/photonizer.py b/photonizer/src/photonizer/photonizer.py
new file mode 100644
index 0000000..465656b
--- /dev/null
+++ b/photonizer/src/photonizer/photonizer.py
@@ -0,0 +1,39 @@
+import numpy as np
+
+from karabo.bound import (
+    NODE_ELEMENT,
+    DOUBLE_ELEMENT
+)
+
+from calng.correction_addons.base_addon import BaseCorrectionAddon
+
+
+class Photonizer(BaseCorrectionAddon):
+    def __init__(self, config):
+        global cupy
+        import cupy
+
+        self._photon_energy = config.get("photonEnergy")
+
+    @staticmethod
+    def extend_device_schema(schema, prefix):
+        (
+            DOUBLE_ELEMENT(schema)
+            .key(f"{prefix}.photonEnergy")
+            .tags("managed")
+            .assignmentOptional()
+            .defaultValue(8.0)
+            .reconfigurable()
+            .commit(),
+        )
+
+    def reconfigure(self, changed_config):
+        if changed_config.has("photonEnergy"):
+            self._photon_energy = changed_config["photonEnergy"]
+
+    def post_correction(self, data, cell_table, pulse_table, output_hash):
+        data /= self._photon_energy
+        np.around(data, out=data)
+
+    def post_reshape(self, data, cell_table, pulse_table, output_hash):
+        print(output_hash["header"].keys())
diff --git a/xpcs/setup.py b/xpcs/setup.py
new file mode 100644
index 0000000..c661daa
--- /dev/null
+++ b/xpcs/setup.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+from os.path import dirname, join, realpath
+from setuptools import setup, find_packages, Extension
+
+from karabo.packaging.versioning import device_scm_version
+
+
+ROOT_FOLDER = dirname(realpath(__file__))
+scm_version = device_scm_version(ROOT_FOLDER, join(ROOT_FOLDER, "src", "_version.py"))
+
+
+setup(
+    name="xpcs",
+    use_scm_version=scm_version,
+    author="James Wrigley",
+    author_email="da-support@xfel.eu",
+    description="",
+    long_description="",
+    url="",
+    package_dir={"": "src"},
+    packages=find_packages("src"),
+    entry_points={
+        "calng.correction_addon": [
+            "Xpcs = xpcs.xpcs:Xpcs",
+        ],
+    },
+    requires=[
+        "fastXPCS"
+    ],
+)
diff --git a/xpcs/src/_version.py b/xpcs/src/_version.py
new file mode 100644
index 0000000..0731bb7
--- /dev/null
+++ b/xpcs/src/_version.py
@@ -0,0 +1,4 @@
+# coding: utf-8
+# file generated by setuptools_scm
+# don't change, don't track in version control
+version = '0.0.1-2.17.0-0-g250da4f-dirty'
diff --git a/xpcs/src/xpcs/xpcs.py b/xpcs/src/xpcs/xpcs.py
new file mode 100644
index 0000000..da7e463
--- /dev/null
+++ b/xpcs/src/xpcs/xpcs.py
@@ -0,0 +1,139 @@
+import time
+from pathlib import Path
+
+import numpy as np
+from karabo.bound import NODE_ELEMENT, NDARRAY_ELEMENT, STRING_ELEMENT
+
+from fastXPCS.algos import TTCdata, do_sparse_train
+from fastXPCS.fxpcs_sparse import sparsify, sparsify2
+from calng.correction_addons.base_addon import BaseCorrectionAddon
+
+
+class Xpcs(BaseCorrectionAddon):
+    def __init__(self, config):
+        self._ttcdata = TTCdata()
+        self._mask_path = config["mask_path"]
+        self._module_no = None
+
+        self._current_image_mean = 0
+        self._current_image = None
+        self._sparse_array = None
+        self._cal_mask = None
+
+        global cupy
+        import cupy
+
+    @staticmethod
+    def extend_device_schema(schema, prefix):
+        (
+            STRING_ELEMENT(schema)
+            .key(f"{prefix}.mask_path")
+            .tags("managed")
+            .assignmentOptional()
+            .defaultValue("")
+            .reconfigurable()
+            .commit(),
+        )
+
+    @staticmethod
+    def extend_output_schema(schema):
+        (
+            NODE_ELEMENT(schema)
+            .key("xpcs")
+            .commit(),
+
+            NDARRAY_ELEMENT(schema)
+            .key("xpcs.ttcf_on")
+            .dtype('FLOAT')
+            .commit(),
+
+            NDARRAY_ELEMENT(schema)
+            .key("xpcs.ttcf_off")
+            .dtype('FLOAT')
+            .commit(),
+        )
+
+    def set_mask(self):
+        if Path(self._mask_path).is_file() and self._module_no is not None:
+            mask = np.load(self._mask_path)
+            self._ttcdata.user_q_mask = mask[:, self._module_no].copy()
+            print(f"Loaded mask for module {self._module_no} with shape {self._ttcdata.user_q_mask.shape}, mean {self._ttcdata.user_q_mask.mean()}")
+
+    def reconfigure(self, changed_config):
+        if changed_config.has("mask_path"):
+            self._mask_path = changed_config["mask_path"]
+            self.set_mask()
+
+    def post_correction(self, data, cell_table, pulse_table, output_hash):
+        global cupy
+
+        # Insert dummy values
+        data[0] = 0
+
+        # Photonize
+        # print(f"Unphotonized mean ({data.shape}): {np.nanmean(data)}")
+        start = time.time()
+        data /= 10
+        data[data < 0] = 0
+        np.around(data, out=data)
+        # print(f"Photonized mean: {np.nanmean(data)}")
+
+        # Sparsify
+        start = time.time()
+        flat_image_shape = data.reshape(data.shape[0], -1).shape
+        reshaped_data = data.reshape(flat_image_shape).T
+        indices = cupy.indices(reshaped_data.shape)
+
+        lit_mask = reshaped_data > 0
+        lit_pixels = reshaped_data[lit_mask].astype(cupy.uint32)
+        lit_indices = indices[:, lit_mask].astype(cupy.uint32)
+
+        lit_pixels_cpu = lit_pixels.get()
+        lit_indices_cpu = lit_indices.get()
+
+        sparse_array = np.empty_like(lit_pixels_cpu, dtype=np.uint32)
+        sparsify2(lit_pixels_cpu, lit_indices_cpu, sparse_array)
+
+        self._current_image = data.astype(cupy.int32).get()
+        self._current_image_mean = np.nanmean(data)
+        self._cal_mask = np.isnan(data).get()
+        self._sparse_array = sparse_array
+        # print(f"Sparsified in {time.time() - start:.3f} down to: {self._sparse_array.shape}")
+
+        if self._module_no == 3:
+            print(f"Found lit pixels: {sparse_array.shape}")
+
+    def post_reshape(self, data, cell_table, pulse_table, output_hash):
+        if self._module_no is None:
+            source = list(self._device.sources)[0]
+            self._module_no = int(source.split("/")[-1].split(":")[0][:-3])
+            self.set_mask()
+
+        if self._module_no != 3 or self._current_image_mean > 20:
+            return
+        
+        # print(f"Processing with mean {self._current_image_mean:.3e} and lit pixels: {self._sparse_array.shape}")
+
+        sparse_ref = sparsify(self._current_image.reshape(self._current_image.shape[0], -1))
+        # print(sparse_ref.shape, self._sparse_array.shape)
+        # if sparse_ref.shape == self._sparse_array.shape:
+        #     print(np.all(np.equal(sparse_ref, self._sparse_array)))
+
+        # print(f"Using lit pixels: {self._sparse_array.shape}")
+        start = time.time()
+        self._ttcdata.current_image = self._current_image
+        self._ttcdata.current_image_sparse = sparse_ref # self._sparse_array
+        self._ttcdata.current_cal_mask = self._cal_mask
+
+        elapsed = time.time() - start
+        # print(f"Init in: {elapsed:.3f}")
+
+        start = time.time()
+        do_sparse_train(self._ttcdata)
+        elapsed = time.time() - start
+        # print(f"TTCF in: {elapsed:.3f}")
+
+        print(np.nanmean(self._ttcdata.ttc_on), self._ttcdata.s_cnt)
+
+        output_hash["xpcs.ttcf_on"] = self._ttcdata.ttc_on.astype(np.int32)
+        # output_hash["xpcs.ttcf_off"] = self._ttcdata.ttc_off.astype(np.int32)
-- 
GitLab