From 1356deb427f36e2d26f44b77bc251de42d700de0 Mon Sep 17 00:00:00 2001
From: ahmedk <karim.ahmed@xfel.eu>
Date: Thu, 14 Jul 2022 00:25:31 +0200
Subject: [PATCH] Retrieve constants from YAML epix/pnccd

---
 .../ePix100/Correction_ePix100_NBC.ipynb      | 172 +++++++++++---
 notebooks/pnCCD/Correct_pnCCD_NBC.ipynb       | 212 ++++++++++--------
 src/cal_tools/pnccdlib.py                     |   6 +-
 src/cal_tools/tools.py                        |   3 +
 4 files changed, 256 insertions(+), 137 deletions(-)

diff --git a/notebooks/ePix100/Correction_ePix100_NBC.ipynb b/notebooks/ePix100/Correction_ePix100_NBC.ipynb
index 396a2ed69..f0cd9cc58 100644
--- a/notebooks/ePix100/Correction_ePix100_NBC.ipynb
+++ b/notebooks/ePix100/Correction_ePix100_NBC.ipynb
@@ -19,6 +19,7 @@
    "source": [
     "in_folder = \"/gpfs/exfel/exp/CALLAB/202031/p900113/raw\"  # input folder, required\n",
     "out_folder = \"\"  # output folder, required\n",
+    "metadata_folder = \"\"  # Directory containing calibration_metadata.yml when run by xfel-calibrate\n",
     "sequences = [-1]  # sequences to correct, set to -1 for all, range allowed\n",
     "sequences_per_node = 1  # number of sequence files per cluster node if run as slurm job, set to 0 to not run SLURM parallel\n",
     "run = 9988  # which run to read data from, required\n",
@@ -77,25 +78,23 @@
    "outputs": [],
    "source": [
     "import tabulate\n",
-    "import traceback\n",
     "import warnings\n",
     "\n",
     "import h5py\n",
     "import pasha as psh\n",
-    "import multiprocessing\n",
     "import numpy as np\n",
     "import matplotlib.pyplot as plt\n",
-    "from IPython.display import Latex, Markdown, display\n",
+    "from IPython.display import Latex, display\n",
     "from extra_data import RunDirectory, H5File\n",
     "from pathlib import Path\n",
     "\n",
     "from XFELDetAna import xfelpyanatools as xana\n",
     "from XFELDetAna import xfelpycaltools as xcal\n",
-    "from XFELDetAna.plotting.util import prettyPlotting\n",
     "from cal_tools import h5_copy_except\n",
     "from cal_tools.tools import (\n",
-    "    get_constant_from_db,\n",
     "    get_dir_creation_date,\n",
+    "    get_from_db,\n",
+    "    CalibrationMetadata,\n",
     ")\n",
     "from cal_tools.step_timing import StepTimer\n",
     "from iCalibrationDB import (\n",
@@ -121,7 +120,7 @@
     "if absolute_gain:\n",
     "    relative_gain = True\n",
     "\n",
-    "plot_unit = 'ADU'\n"
+    "plot_unit = 'ADU'"
    ]
   },
   {
@@ -136,6 +135,39 @@
     "in_folder = Path(in_folder)\n",
     "ped_dir = in_folder / f\"r{run:04d}\"\n",
     "run_dc = RunDirectory(ped_dir, _use_voview=False)\n",
+    "metadata = CalibrationMetadata(metadata_folder or out_folder)\n",
+    "# NOTE: this notebook will not overwrite calibration metadata file\n",
+    "const_yaml = metadata.get(\"retrieved-constants\", {})\n",
+    "\n",
+    "fp_name = path_template.format(run, karabo_da)\n",
+    "\n",
+    "print(f\"Reading from: {ped_dir / fp_name}\")\n",
+    "print(f\"Run is: {run}\")\n",
+    "print(f\"Instrument H5File source: {instrument_src}\")\n",
+    "print(f\"Data corrected files are stored at: {out_folder}\")\n",
+    "\n",
+    "creation_time = None\n",
+    "if use_dir_creation_date:\n",
+    "    creation_time = get_dir_creation_date(in_folder, run)\n",
+    "if creation_time:\n",
+    "    print(f\"Using {creation_time.isoformat()} as creation time\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "x = 708  # rows of the ePix100\n",
+    "y = 768  # columns of the ePix100\n",
+    "\n",
+    "in_folder = Path(in_folder)\n",
+    "ped_dir = in_folder / f\"r{run:04d}\"\n",
+    "run_dc = RunDirectory(ped_dir, _use_voview=False)\n",
+    "metadata = CalibrationMetadata(metadata_folder or out_folder)\n",
+    "# NOTE: this notebook will not overwrite calibration metadata file\n",
+    "const_yaml = metadata.get(\"retrieved-constants\", {})\n",
     "\n",
     "fp_name = path_template.format(run, karabo_da)\n",
     "\n",
@@ -264,6 +296,10 @@
     "}\n",
     "\n",
     "dark_condition = Conditions.Dark.ePix100(**cond_dict)\n",
+    "for parm in dark_condition.parameters:\n",
+    "    if parm.name == \"Sensor Temperature\":\n",
+    "        parm.lower_deviation = temp_deviations\n",
+    "        parm.upper_deviation = temp_deviations\n",
     "\n",
     "# update conditions with illuminated conditins.\n",
     "cond_dict.update({\n",
@@ -276,38 +312,96 @@
     "    \"Offset\": dark_condition,\n",
     "    \"Noise\": dark_condition,\n",
     "    \"RelativeGain\": illum_condition,\n",
-    "}\n",
-    "\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
     "const_data = dict()\n",
+    "when = dict()\n",
+    "# Constant paths are saved under retrieved-constants in calibration_metadata.yml\n",
+    "retrieved_constants = metadata.setdefault(\"retrieved-constants\", {})\n",
+    "\n",
+    "if const_yaml:  #  Used while reproducing corrected data.\n",
+    "    print(f\"Using stored constants in {metadata.yamlfile}\")\n",
+    "    for cname, mdata in const_yaml[karabo_da][\"constants\"].items():\n",
+    "        const_data[cname] = dict()\n",
+    "        when[cname] = mdata[\"creation-time\"]\n",
+    "        if when[cname]:\n",
+    "            with h5py.File(mdata[\"file-path\"], \"r\") as cf:\n",
+    "                const_data[cname] = np.copy(\n",
+    "                    cf[f\"{mdata['dataset-name']}/data\"])\n",
+    "        else:\n",
+    "            const_data[cname] = None\n",
+    "else:  # First correction attempt.\n",
+    "    mdata_dict = dict()\n",
+    "    mdata_dict[\"constants\"] = dict()\n",
+    "    for cname, condition in const_cond.items():\n",
+    "        mdata_dict[\"constants\"][cname] = dict()\n",
+    "        # Avoid retrieving RelativeGain, if not needed for correction.\n",
+    "        if cname == \"RelativeGain\" and not relative_gain:\n",
+    "            const_data[cname] = None\n",
+    "        else:\n",
+    "            const_data[cname], mdata = get_from_db(\n",
+    "                karabo_id=karabo_id,\n",
+    "                karabo_da=karabo_da,\n",
+    "                constant=getattr(Constants.ePix100, cname)(),\n",
+    "                condition=condition,\n",
+    "                empty_constant=None,\n",
+    "                cal_db_interface=cal_db_interface,\n",
+    "                creation_time=creation_time,\n",
+    "                verbosity=2,\n",
+    "                timeout=cal_db_timeout,\n",
+    "                meta_only=True,\n",
+    "            )\n",
+    "        mdata_const = mdata.calibration_constant_version\n",
+    "        const_mdata = mdata_dict[\"constants\"][cname]\n",
+    "        # check if constant was successfully retrieved.\n",
+    "        if mdata.comm_db_success:\n",
+    "            const_mdata[\"file-path\"] = (\n",
+    "                f\"{mdata_const.hdf5path}\" f\"{mdata_const.filename}\"\n",
+    "            )\n",
+    "            const_mdata[\"dataset-name\"] = mdata_const.h5path\n",
+    "            const_mdata[\"creation-time\"] = f\"{mdata_const.begin_at}\"\n",
+    "            mdata_dict[\"physical-detector-unit\"] = mdata_const.device_name\n",
+    "        else:\n",
+    "            const_mdata[\"file-path\"] = None\n",
+    "            const_mdata[\"creation-time\"] = None"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Store constants metadata in the corresponding calibration_metadata.yml file.\n",
+    "if not const_yaml:\n",
+    "    retrieved_constants[karabo_da] = mdata_dict\n",
     "\n",
-    "for cname, condition in const_cond.items():\n",
-    "    if cname == \"RelativeGain\" and not relative_gain:\n",
-    "        continue\n",
-    "    # TODO: Fix this logic.\n",
-    "    for parm in condition.parameters:\n",
-    "        if parm.name == \"Sensor Temperature\":\n",
-    "            parm.lower_deviation = temp_deviations\n",
-    "            parm.upper_deviation = temp_deviations\n",
-    "\n",
-    "    const_data[cname] = get_constant_from_db(\n",
-    "        karabo_id=karabo_id,\n",
-    "        karabo_da=karabo_da,\n",
-    "        constant=getattr(Constants.ePix100, cname)(),\n",
-    "        condition=condition,\n",
-    "        empty_constant=None,\n",
-    "        cal_db_interface=cal_db_interface,\n",
-    "        creation_time=creation_time,\n",
-    "        print_once=2,\n",
-    "        timeout=cal_db_timeout\n",
-    "    )\n",
+    "    timestamps = dict()\n",
     "\n",
-    "if relative_gain and const_data[\"RelativeGain\"] is None:\n",
-    "    print(\n",
-    "        \"WARNING: RelativeGain map is requested, but not found.\\n\"\n",
-    "        \"No gain correction will be applied\"\n",
-    "    )\n",
-    "    relative_gain = False\n",
-    "    absolute_gain = False\n"
+    "    module_timestamps = timestamps[karabo_da] = dict()\n",
+    "    module_constants = retrieved_constants[karabo_da]\n",
+    "\n",
+    "    for cname, mdata in module_constants[\"constants\"].items():\n",
+    "        if hasattr(mdata[\"creation-time\"], 'strftime'):\n",
+    "            mdata[\"creation-time\"] = mdata[\"creation-time\"].strftime('%y-%m-%d %H:%M')\n",
+    "\n",
+    "    for cname in [\"Offset\", \"BadPixelsDark\", \"RelativeGain\"]:\n",
+    "        if cname in module_constants[\"constants\"]:\n",
+    "            module_timestamps[cname] = module_constants[\"constants\"][cname][\"creation-time\"]\n",
+    "        else:\n",
+    "            module_timestamps[cname] = \"NA\"\n",
+    "\n",
+    "    time_summary = retrieved_constants.setdefault(\"time-summary\", {})\n",
+    "    time_summary[\"SAll\"] = timestamps\n",
+    "    metadata.save()\n",
+    "    print(f\"Stored retrieved constants in {metadata.yamlfile}\")"
    ]
   },
   {
@@ -316,6 +410,14 @@
    "metadata": {},
    "outputs": [],
    "source": [
+    "if relative_gain and const_data.get(\"RelativeGain\", None) is None:\n",
+    "    print(\n",
+    "        \"WARNING: RelativeGain map is requested, but not found.\\n\"\n",
+    "        \"No gain correction will be applied\"\n",
+    "    )\n",
+    "    relative_gain = False\n",
+    "    absolute_gain = False\n",
+    "\n",
     "# Initializing some parameters.\n",
     "hscale = 1\n",
     "stats = True\n",
diff --git a/notebooks/pnCCD/Correct_pnCCD_NBC.ipynb b/notebooks/pnCCD/Correct_pnCCD_NBC.ipynb
index c1350f12e..cedfdd1c9 100644
--- a/notebooks/pnCCD/Correct_pnCCD_NBC.ipynb
+++ b/notebooks/pnCCD/Correct_pnCCD_NBC.ipynb
@@ -18,7 +18,8 @@
    "outputs": [],
    "source": [
     "in_folder = \"/gpfs/exfel/exp/SQS/202031/p900166/raw\"  # input folder\n",
-    "out_folder = \"/gpfs/exfel/data/scratch/ahmedk/test/remove\"  # output folder\n",
+    "out_folder = \"/gpfs/exfel/data/scratch/ahmedk/test/remove/pnccd_correct\"  # output folder\n",
+    "metadata_folder = \"\"  # Directory containing calibration_metadata.yml when run by xfel-calibrate\n",
     "run = 347  # which run to read data from\n",
     "sequences = [-1]  # sequences to correct, set to -1 for all, range allowed\n",
     "sequences_per_node = 1  # number of sequences running on the same slurm node.\n",
@@ -98,7 +99,6 @@
     "import os\n",
     "import warnings\n",
     "from pathlib import Path\n",
-    "from typing import Tuple\n",
     "warnings.filterwarnings('ignore')\n",
     "\n",
     "import h5py\n",
@@ -115,14 +115,14 @@
     "from XFELDetAna import xfelpycaltools as xcal\n",
     "from cal_tools import pnccdlib\n",
     "from cal_tools.tools import (\n",
-    "    get_constant_from_db_and_time,\n",
     "    get_dir_creation_date,\n",
+    "    get_from_db,\n",
     "    get_random_db_interface,\n",
-    "    map_modules_from_folder,\n",
+    "    CalibrationMetadata,\n",
     ")\n",
     "from cal_tools.step_timing import StepTimer\n",
     "from cal_tools import h5_copy_except\n",
-    "from iCalibrationDB import Conditions, ConstantMetaData, Constants\n",
+    "from iCalibrationDB import Conditions, Constants\n",
     "from iCalibrationDB.detectors import DetectorTypes"
    ]
   },
@@ -184,6 +184,9 @@
    "source": [
     "run_dc = RunDirectory(Path(in_folder) / f\"r{run:04d}\", _use_voview=False)\n",
     "ctrl_data = pnccdlib.PnccdCtrl(run_dc, karabo_id)\n",
+    "metadata = CalibrationMetadata(metadata_folder or out_folder)\n",
+    "# NOTE: this notebook will not overwrite calibration metadata file\n",
+    "const_yaml = metadata.get(\"retrieved-constants\", {})\n",
     "\n",
     "# extract control data\n",
     "step_timer.start()\n",
@@ -314,7 +317,10 @@
    "outputs": [],
    "source": [
     "# Output Folder Creation:\n",
-    "os.makedirs(out_folder, exist_ok=True if overwrite else False)"
+    "os.makedirs(out_folder, exist_ok=True if overwrite else False)\n",
+    "\n",
+    "# Constant paths are saved under retrieved-constants in calibration_metadata.yml\n",
+    "retrieved_constants = metadata.setdefault(\"retrieved-constants\", {})"
    ]
   },
   {
@@ -330,57 +336,105 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "def get_dark(db_parms: Tuple[str, int], bias_voltage: float, gain: float, integration_time: float,\n",
-    "             fix_temperature_top: float, creation_time: str, run: str) -> dict :\n",
-    "# This function is to retrieve the dark constants associated with the run of interest:\n",
-    "\n",
-    "    cal_db_interface, cal_db_timeout = db_parms\n",
-    "    cal_db_interface = get_random_db_interface(cal_db_interface)\n",
-    "    print(f'Calibration database interface: {cal_db_interface}')\n",
-    "        \n",
-    "    try:    \n",
-    "        Offset = None\n",
-    "        Noise = None\n",
-    "        BadPixelsDark = None\n",
-    "\n",
-    "        constants = {} \n",
-    "        constants['Offset'] = Offset\n",
-    "        constants['Noise'] = Noise\n",
-    "        constants['BadPixelsDark'] = BadPixelsDark\n",
-    "        when = {}\n",
-    "        \n",
-    "        condition = Conditions.Dark.CCD(bias_voltage=bias_voltage,\n",
-    "                                        integration_time=integration_time,\n",
-    "                                        gain_setting=gain,\n",
-    "                                        temperature=fix_temperature_top,\n",
-    "                                        pixels_x=pixels_x,\n",
-    "                                        pixels_y=pixels_y)\n",
-    "        \n",
-    "        for const in constants.keys():\n",
-    "            constants[const], when[const] = \\\n",
-    "                get_constant_from_db_and_time(karabo_id, karabo_da,\n",
-    "                                      getattr(Constants.CCD(DetectorTypes.pnCCD), const)(),\n",
-    "                                      condition,\n",
-    "                                      np.zeros((pixels_x, pixels_y, 1)),\n",
-    "                                      cal_db_interface,\n",
-    "                                      creation_time=creation_time)\n",
-    "        for parm in condition.parameters:\n",
-    "            if parm.name == \"Sensor Temperature\":\n",
-    "                print(f\"For run {run}: dark images for offset calculation \" \n",
-    "                      f\"were taken at temperature: {parm.value:0.2f} \"\n",
-    "                      f\"K @ {when['Offset']}\")\n",
-    "    except Exception as e:\n",
-    "        print(f\"Error: {e}\")\n",
-    "\n",
+    "display(Markdown('### Constants retrieval'))\n",
+    "step_timer.start()\n",
     "\n",
-    "    return constants"
+    "conditions_dict = {\n",
+    "    \"bias_voltage\": bias_voltage,\n",
+    "    \"integration_time\": integration_time,\n",
+    "    \"gain_setting\": gain,\n",
+    "    \"temperature\": fix_temperature_top,\n",
+    "    \"pixels_x\": pixels_x,\n",
+    "    \"pixels_y\": pixels_y,\n",
+    "    }\n",
+    "# Dark condition\n",
+    "dark_condition = Conditions.Dark.CCD(**conditions_dict)\n",
+    "# Add photon energy.\n",
+    "conditions_dict.update({\"photon_energy\": photon_energy})\n",
+    "illum_condition = Conditions.Illuminated.CCD(**conditions_dict)\n",
+    "\n",
+    "constants = dict()\n",
+    "when = dict()\n",
+    "init_constants = {  # A dictionary for initializing constants. {cname: (empty_constants, condition)}  # noqa\n",
+    "    \"Offset\": (np.zeros((pixels_x, pixels_y, 1), dtype=np.float32), dark_condition),  # noqa\n",
+    "    \"Noise\": (np.zeros((pixels_x, pixels_y, 1), dtype=np.float32), dark_condition),  # noqa\n",
+    "    \"BadPixelsDark\": (np.zeros((pixels_x, pixels_y, 1), dtype=np.uint32), dark_condition),  # noqa\n",
+    "    \"RelativeGain\": (np.zeros((pixels_x, pixels_y), dtype=np.float32), illum_condition),  # noqa\n",
+    "}\n",
+    "if const_yaml:  #  Used while reproducing corrected data.\n",
+    "    print(f\"Using stored constants in {metadata.filename}\")\n",
+    "    for cname, mdata in const_yaml[karabo_da][\"constants\"].items():\n",
+    "        constants[cname] = dict()\n",
+    "        when[cname] = mdata[\"creation-time\"]\n",
+    "        if when[cname]:\n",
+    "            with h5py.File(mdata[\"file-path\"], \"r\") as cf:\n",
+    "                constants[cname] = np.copy(\n",
+    "                    cf[f\"{mdata['dataset-name']}/data\"])\n",
+    "        else:\n",
+    "            constants[cname] = init_constants[cname][0]\n",
+    "else:\n",
+    "    mdata_dict = dict()\n",
+    "    mdata_dict[\"constants\"] = dict()\n",
+    "    for cname, cval in init_constants.items():\n",
+    "        mdata_dict[\"constants\"][cname] = dict()\n",
+    "        # No need for retrieving RelativeGain, if not used for correction.\n",
+    "        if not corr_bools.get(\"relgain\") and cname == \"RelativeGain\":\n",
+    "            continue\n",
+    "        constants[cname], mdata = \\\n",
+    "            get_from_db(\n",
+    "                karabo_id=karabo_id,\n",
+    "                karabo_da=karabo_da,\n",
+    "                constant=getattr(Constants.CCD(DetectorTypes.pnCCD), cname)(),\n",
+    "                condition=cval[1],\n",
+    "                empty_constant=cval[0],\n",
+    "                cal_db_interface=get_random_db_interface(cal_db_interface),\n",
+    "                creation_time=creation_time,\n",
+    "                verbosity=1,\n",
+    "            )\n",
+    "        mdata_const = mdata.calibration_constant_version\n",
+    "        const_mdata = mdata_dict[\"constants\"][cname]\n",
+    "        # check if constant was successfully retrieved.\n",
+    "        if mdata.comm_db_success:\n",
+    "            const_mdata[\"file-path\"] = (\n",
+    "                f\"{mdata_const.hdf5path}\" f\"{mdata_const.filename}\"\n",
+    "            )\n",
+    "            const_mdata[\"dataset-name\"] = mdata_const.h5path\n",
+    "            const_mdata[\"creation-time\"] = f\"{mdata_const.begin_at}\"\n",
+    "            mdata_dict[\"physical-detector-unit\"] = mdata_const.device_name\n",
+    "        else:\n",
+    "            const_mdata[\"file-path\"] = None\n",
+    "            const_mdata[\"creation-time\"] = None\n"
    ]
   },
   {
-   "cell_type": "markdown",
+   "cell_type": "code",
+   "execution_count": null,
    "metadata": {},
+   "outputs": [],
    "source": [
-    "## Retrieving calibration constants"
+    "# Store constants metadata in the corresponding calibration_metadata.yml file.\n",
+    "if not const_yaml:\n",
+    "    retrieved_constants[karabo_da] = mdata_dict\n",
+    "\n",
+    "    timestamps = dict()\n",
+    "\n",
+    "    module_timestamps = timestamps[karabo_da] = dict()\n",
+    "    module_constants = retrieved_constants[karabo_da]\n",
+    "\n",
+    "    for cname, mdata in module_constants[\"constants\"].items():\n",
+    "        if hasattr(mdata[\"creation-time\"], 'strftime'):\n",
+    "            mdata[\"creation-time\"] = mdata[\"creation-time\"].strftime('%y-%m-%d %H:%M')\n",
+    "\n",
+    "    for cname in [\"Offset\", \"BadPixelsDark\", \"RelativeGain\"]:\n",
+    "        if cname in module_constants[\"constants\"]:\n",
+    "            module_timestamps[cname] = module_constants[\"constants\"][cname][\"creation-time\"]\n",
+    "        else:\n",
+    "            module_timestamps[cname] = \"NA\"\n",
+    "\n",
+    "    time_summary = retrieved_constants.setdefault(\"time-summary\", {})\n",
+    "    time_summary[\"SAll\"] = timestamps\n",
+    "    metadata.save()\n",
+    "    print(f\"Stored retrieved constants in {metadata.filename}\")"
    ]
   },
   {
@@ -389,13 +443,6 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "display(Markdown('### Dark constants retrieval'))\n",
-    "step_timer.start()\n",
-    "db_parms = cal_db_interface, cal_db_timeout\n",
-    "\n",
-    "constants = get_dark(db_parms, bias_voltage, gain, integration_time,\n",
-    "                     fix_temperature_top, creation_time, run)\n",
-    "\n",
     "fig = xana.heatmapPlot(constants[\"Offset\"][:,:,0], x_label='Columns', y_label='Rows', lut_label='Offset (ADU)', \n",
     "                       aspect=1, \n",
     "                       x_range=(0, pixels_y), y_range=(0, pixels_x), vmax=16000, \n",
@@ -413,49 +460,16 @@
     "                       aspect=1, x_range=(0, pixels_y), y_range=(0, pixels_x), \n",
     "                       panel_x_label='Row Stat (ADU)', panel_y_label='Column Stat (ADU)', \n",
     "                       title = 'Dark Bad Pixels Map')\n",
-    "step_timer.done_step(\"Dark constants retrieval\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
+    "\n",
     "if corr_bools.get('relgain'):\n",
-    "    step_timer.start()\n",
-    "    display(Markdown('### Relative gain constant retrieval'))\n",
-    "    metadata = ConstantMetaData()\n",
-    "    relgain = Constants.CCD(DetectorTypes.pnCCD).RelativeGain()\n",
-    "    metadata.calibration_constant = relgain\n",
-    "    # set the operating condition\n",
-    "    condition = Conditions.Illuminated.CCD(bias_voltage=bias_voltage,\n",
-    "                                           integration_time=integration_time,\n",
-    "                                           gain_setting=gain,\n",
-    "                                           temperature=fix_temperature_top,\n",
-    "                                           pixels_x=pixels_x,\n",
-    "                                           pixels_y=pixels_y, \n",
-    "                                           photon_energy=photon_energy)\n",
-    "\n",
-    "    constants[\"RelativeGain\"], relgain_time = \\\n",
-    "        get_constant_from_db_and_time(karabo_id, karabo_da,\n",
-    "                                      Constants.CCD(DetectorTypes.pnCCD).RelativeGain(),\n",
-    "                                      condition,\n",
-    "                                      np.zeros((pixels_x, pixels_y)),\n",
-    "                                      cal_db_interface,\n",
-    "                                      creation_time=creation_time)\n",
-    "\n",
-    "    print(f\"Retrieved RelativeGain constant with creation time: {relgain_time}\")\n",
-    "\n",
-    "    display(Markdown('### Relative Gain Map Retrieval'))\n",
     "    fig = xana.heatmapPlot(constants[\"RelativeGain\"], figsize=(8, 8), x_label='Columns', y_label='Rows', \n",
-    "                           lut_label='Relative Gain', \n",
-    "                           aspect=1, x_range=(0, pixels_y), y_range=(0, pixels_x), vmin=0.8, vmax=1.2, \n",
-    "                           panel_x_label='Row Stat (ADU)', panel_y_label='Column Stat (ADU)', \n",
-    "                           panel_top_low_lim = 0.5, panel_top_high_lim = 1.5, panel_side_low_lim = 0.5, \n",
-    "                           panel_side_high_lim = 1.5, \n",
-    "                           title = f'Relative Gain Map for pnCCD (Gain = 1/{int(gain)})')\n",
-    "    step_timer.done_step(\"Relative gain constant retrieval\")"
+    "                            lut_label='Relative Gain', \n",
+    "                            aspect=1, x_range=(0, pixels_y), y_range=(0, pixels_x), vmin=0.8, vmax=1.2, \n",
+    "                            panel_x_label='Row Stat (ADU)', panel_y_label='Column Stat (ADU)', \n",
+    "                            panel_top_low_lim = 0.5, panel_top_high_lim = 1.5, panel_side_low_lim = 0.5, \n",
+    "                            panel_side_high_lim = 1.5, \n",
+    "                            title = f'Relative Gain Map for pnCCD (Gain = 1/{int(gain)})')\n",
+    "step_timer.done_step(\"Constants retrieval\")"
    ]
   },
   {
diff --git a/src/cal_tools/pnccdlib.py b/src/cal_tools/pnccdlib.py
index 98594427e..4a9c298ca 100644
--- a/src/cal_tools/pnccdlib.py
+++ b/src/cal_tools/pnccdlib.py
@@ -24,9 +24,9 @@ class PnccdCtrl():
         self.mdl_src_temp = f"{karabo_id}/MDL/{{}}"
 
     def get_bias_voltage(self):
-        return(
-            abs(self.run_dc.get_run_value(
-                self.mdl_src_temp.format("DAQ_MPOD"), "u0voltage.value")))
+        # Convert the high float precision is not needed.
+        return(int(abs(self.run_dc.get_run_value(
+            self.mdl_src_temp.format("DAQ_MPOD"), "u0voltage.value"))))
 
     def get_gain(self):
         return(
diff --git a/src/cal_tools/tools.py b/src/cal_tools/tools.py
index db913f26f..c489f48b3 100644
--- a/src/cal_tools/tools.py
+++ b/src/cal_tools/tools.py
@@ -872,6 +872,9 @@ class CalibrationMetadata(dict):
                 else:
                     print(f"Warning: existing {self._yaml_fn} is malformed, "
                            "will be overwritten")
+    @property
+    def filename(self):
+        return self._yaml_fn
 
     def save(self):
         with self._yaml_fn.open("w") as fd:
-- 
GitLab