diff --git a/notebooks/Gotthard2/Characterize_Darks_Gotthard2_NBC.ipynb b/notebooks/Gotthard2/Characterize_Darks_Gotthard2_NBC.ipynb index e7dbfc9cd26bebd5e62d440c3971a9edfd3613fe..bf2384afb09c59108e739a9ab9493d8adaf8f7b8 100644 --- a/notebooks/Gotthard2/Characterize_Darks_Gotthard2_NBC.ipynb +++ b/notebooks/Gotthard2/Characterize_Darks_Gotthard2_NBC.ipynb @@ -52,7 +52,7 @@ "acquisition_rate = -1. # Detector acquisition rate (1.1/4.5), set to -1 to use value in raw file.\n", "single_photon = -1 # Detector single photon mode (High/Low CDS), set to -1 to use value in raw file.\n", "# This is used for the summary notebook\n", - "gh2_detector = \"\" # Specifies the GH2 detector type ('50um' or '25um'). This parameter can be used to manually set the detector type if the code cannot automatically determine it from the control data.\n", + "sensor_type = \"\" # Specifies the GH2 sensor type: '50um', '25um', or \"\" to automatically decide from RUN data.\n", "\n", "# Parameters used for calculating calibration constants\n", "bpix_noise_nitrs = 5 # number of maximum iterations to actively try to reach correct number of badpixels of NOISE_OUT_OF_THRESHOLD type. Leave -1 to keep iterating until finding maximum number of badpixels.\n", @@ -208,9 +208,9 @@ "print(\"Single photon: \", single_photon)\n", "acquisition_rate = conditions[\"acquisition_rate\"].pop()\n", "print(\"Acquisition rate: \", acquisition_rate)\n", - "if not gh2_detector:\n", - " gh2_detector = g2ctrl.get_det_type()\n", - "print(f\"Processing {gh2_detector} Gotthard2.\")" + "if not sensor_type:\n", + " sensor_type = g2ctrl.get_sensor_type()\n", + "print(f\"Processing {sensor_type} Gotthard2.\")" ] }, { diff --git a/notebooks/Gotthard2/Correction_Gotthard2_NBC.ipynb b/notebooks/Gotthard2/Correction_Gotthard2_NBC.ipynb index 022c74bfff23567dda077fcf563400eada501c6d..478719287185de554a953965039c62d6550ee8b6 100644 --- a/notebooks/Gotthard2/Correction_Gotthard2_NBC.ipynb +++ b/notebooks/Gotthard2/Correction_Gotthard2_NBC.ipynb @@ -84,7 +84,7 @@ "acquisition_rate = -1. # Detector acquisition rate (1.1/4.5), set to -1 to use value in raw file.\n", "single_photon = -1 # Detector single photon mode (High/Low CDS), set to -1 to use value in raw file.\n", "reverse_second_module = -1 # Reverse 25um GH2 second module before interleaving. set to -1 to use value in raw file to reverse based on `CTRL/reverseSlaveReadOutMode`'s value.\n", - "gh2_detector = \"\" # Specifies the GH2 detector type ('50um' or '25um'). This parameter can be used to manually set the detector type if the code cannot automatically determine it from the control data.\n", + "sensor_type = \"\" # Specifies the GH2 sensor type: '50um', '25um', or \"\" to automatically decide from RUN data.\n", "\n", "# Parameters for plotting\n", "skip_plots = False # exit after writing corrected files\n", @@ -189,17 +189,17 @@ " acquisition_rate = g2ctrl.get_acquisition_rate()\n", "if single_photon == -1:\n", " single_photon = g2ctrl.get_single_photon()\n", - "if not gh2_detector:\n", - " gh2_detector = g2ctrl.get_det_type()\n", + "if not sensor_type:\n", + " sensor_type = g2ctrl.get_sensor_type()\n", "\n", "# Check if the GH2 detector type is \"50um\" and validate that only one data aggregator is provided\n", - "if gh2_detector == \"50um\" and len(karabo_da) > 1:\n", + "if sensor_type == \"50um\" and len(karabo_da) > 1:\n", " raise ValueError(\n", " f\"karabo_da has more than one aggregator {karabo_da}, \"\n", " \"but the GH2 detector type is specified as '50um', which expects only one aggregator.\"\n", " )\n", "\n", - "if reverse_second_module == -1 and gh2_detector == \"25um\":\n", + "if reverse_second_module == -1 and sensor_type == \"25um\":\n", " reverse_second_module = not g2ctrl.second_module_reversed()\n", " if reverse_second_module:\n", " warning(\n", @@ -211,7 +211,7 @@ "print(\"Exposure Period:\", exposure_period)\n", "print(\"Acquisition Rate:\", acquisition_rate)\n", "print(\"Single Photon:\", single_photon)\n", - "print(f\"Processing {gh2_detector} Gotthard2.\")" + "print(f\"Processing {sensor_type} Gotthard2.\")" ] }, { @@ -444,7 +444,7 @@ " print(f\"Correcting {n_trains} for {raw_file}.\")\n", "\n", " # Initialize GH2 data and gain arrays to store in corrected files.\n", - " if gh2_detector == \"25um\":\n", + " if sensor_type == \"25um\":\n", " dshape_stored = (dc[data_sources[0], \"data.adc\"].shape[:2] + (1280 * 2,))\n", " data_stored = np.zeros(dshape_stored, dtype=np.float32)\n", " gain_stored = np.zeros(dshape_stored, dtype=np.uint8)\n", @@ -486,7 +486,7 @@ " # Create CORR files and add corrected data sections.\n", " image_counts = dc[src, \"data.adc\"].data_counts(labelled=False)\n", "\n", - " if gh2_detector == \"25um\":\n", + " if sensor_type == \"25um\":\n", " data_stored[..., i::2] = data_corr\n", " gain_stored[..., i::2] = gain\n", " mask_stored[..., i::2] = mask\n", @@ -577,14 +577,14 @@ " )\n", " mask = out_dc[corr_data_source, \"data.mask\"].train_from_id(tid)[1]\n", "\n", - "if gh2_detector == \"25um\":\n", + "if sensor_type == \"25um\":\n", " mod_dcs[corr_data_source][\"train_raw_data\"] = np.zeros((data_corr.shape[1], 1280 * 2), dtype=np.float32)\n", " mod_dcs[corr_data_source][\"train_raw_gain\"] = np.zeros((data_corr.shape[1], 1280 * 2), dtype=np.uint8)\n", "\n", "for i, src in enumerate(data_sources):\n", " with H5File(first_seq_raw) as in_dc:\n", " train_dict = in_dc.train_from_id(tid)[1][src]\n", - " if gh2_detector == \"25um\":\n", + " if sensor_type == \"25um\":\n", " if reverse_second_module and i == 1:\n", " data = np.flip(train_dict[\"data.adc\"], axis=-1)\n", " gain = np.flip(train_dict[\"data.gain\"], axis=-1)\n", @@ -621,8 +621,8 @@ "display(Markdown(\"### Mean RAW and CORRECTED across pulses for one train:\"))\n", "display(Markdown(f\"Train: {tid}\"))\n", "\n", - "# Set title format based on gh2_detector\n", - "if gh2_detector == \"50um\":\n", + "# Set title format based on sensor_type\n", + "if sensor_type == \"50um\":\n", " title_format = f\"{{}} data for {karabo_da} ({db_modules})\"\n", "else:\n", " title_format = f\"Interleaved {{}} data for {karabo_da} ({db_modules})\"\n", diff --git a/notebooks/Gotthard2/Summary_Darks_Gotthard2_NBC.ipynb b/notebooks/Gotthard2/Summary_Darks_Gotthard2_NBC.ipynb index b4f6df31e0331831a8248d7d93fc6935c7abb7ff..ecd41edee72cadf063920f14a6fb93432014b300 100644 --- a/notebooks/Gotthard2/Summary_Darks_Gotthard2_NBC.ipynb +++ b/notebooks/Gotthard2/Summary_Darks_Gotthard2_NBC.ipynb @@ -31,7 +31,7 @@ "ctrl_source_template = '{karabo_id}/DET/{control_template}' # template for control source name (filled with karabo_id_control)\n", "karabo_id_control = \"\" # Control karabo ID. Set to empty string to use the karabo-id\n", "\n", - "gh2_detector = \"\" # Specifies the GH2 detector type ('50um' or '25um'). This parameter can be used to manually set the detector type if the code cannot automatically determine it from the control data.\n", + "sensor_type = \"\" # Specifies the GH2 sensor type: '50um', '25um', or \"\" to automatically decide from RUN data.\n", "\n", "# Parameters to be used for injecting dark calibration constants.\n", "local_output = True # Boolean indicating that local constants were stored in the out_folder\n", @@ -93,12 +93,9 @@ " karabo_id_control=karabo_id_control,\n", " control_template=control_template\n", " ))\n", - "if not gh2_detector:\n", - " # Unfortunately we can't check if we can't validate this value\n", - " # as the notebook will have only one karabo_da anyway.\n", - " # Dark processing split nodes over each karabo_da\n", - " gh2_detector = g2ctrl.get_det_type()\n", - "print(f\"Processing {gh2_detector} Gotthard2.\")" + "if not sensor_type:\n", + " sensor_type = g2ctrl.get_sensor_type()\n", + "print(f\"Processing {sensor_type} Gotthard2.\")" ] }, { diff --git a/src/cal_tools/gotthard2/gotthard2lib.py b/src/cal_tools/gotthard2/gotthard2lib.py index e6a8267c86de2b567a1e613120f6cde3f16fd226..e13e5ad1e142c123a9dc387f2c91a0141d14574b 100644 --- a/src/cal_tools/gotthard2/gotthard2lib.py +++ b/src/cal_tools/gotthard2/gotthard2lib.py @@ -63,16 +63,31 @@ class Gotthard2Ctrl(): return bool( self.run_dc[self.ctrl_src, "singlePhoton"].as_single_value()) - def get_det_type(self): + def get_sensor_type(self): """GH2 rxHostname is a vector of bytes objects. GH2 25um has two host names unlike 50um which has one. Returns: str: return if its a 25um or 50um detector. """ - - hostname = self.run_dc.get_run_value(self.ctrl_src, "rxHostname") - return "25um" if hostname[1].decode("utf-8") else "50um" + import numpy as np + + hostnames = self.run_dc.get_run_value(self.ctrl_src, "rxHostname") + num_hosts = np.count_nonzero(hostnames != b'') + if num_hosts == 0: + raise ValueError( + "No hosts are present in RUN/rxHostname. " + "Unable to determine the sensor type for this data. ") + + if num_hosts == 1: + return "50um" + elif num_hosts == 2: + return "25um" + else: + raise ValueError( + f"RUN/rxHostname has more host names ({num_hosts}) than expected. " + "Expected either 1 hostname for 50um or 2 host names for 25um." + ) def second_module_reversed(self): """Check if reverseSlaveReadOutMode is True."""