diff --git a/notebooks/AGIPD/AGIPD_Correct_and_Verify.ipynb b/notebooks/AGIPD/AGIPD_Correct_and_Verify.ipynb index dae62fab736d82aa5fa07a4cfc25d934ad21f9c2..aeafce49cdd1c00adea7ea7433fc4ef4ff5360c4 100644 --- a/notebooks/AGIPD/AGIPD_Correct_and_Verify.ipynb +++ b/notebooks/AGIPD/AGIPD_Correct_and_Verify.ipynb @@ -18,7 +18,7 @@ "outputs": [], "source": [ "in_folder = \"/gpfs/exfel/exp/MID/202201/p002834/raw\" # the folder to read data from, required\n", - "out_folder = \"/gpfs/exfel/data/scratch/ahmedk/test/AGIPD_\" # the folder to output to, required\n", + "out_folder = \"/gpfs/exfel/data/scratch/esobolev/pycal_litfrm/p002834/r0225\" # the folder to output to, 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", "modules = [-1] # modules to correct, set to -1 for all, range allowed\n", @@ -36,18 +36,19 @@ "\n", "slopes_ff_from_files = \"\" # Path to locally stored SlopesFF and BadPixelsFF constants, loaded in precorrection notebook\n", "\n", - "creation_time = \"\" # To overwrite the measured creation_time. Required Format: YYYY-MM-DD HR:MN:SC e.g. \"2022-06-28 13:00:00\"\n", + "use_dir_creation_date = True # use the creation data of the input dir for database queries\n", "cal_db_interface = \"tcp://max-exfl016:8015#8045\" # the database interface to use\n", "cal_db_timeout = 30000 # in milliseconds\n", "creation_date_offset = \"00:00:00\" # add an offset to creation date, e.g. to get different constants\n", "\n", - "mem_cells = -1 # Number of memory cells used, set to 0 to automatically infer\n", - "bias_voltage = -1 # bias voltage, set to 0 to use stored value in slow data.\n", - "acq_rate = -1. # the detector acquisition rate, use 0 to try to auto-determine\n", + "mem_cells = 0 # Number of memory cells used, set to 0 to automatically infer\n", + "bias_voltage = 0 # bias voltage, set to 0 to use stored value in slow data.\n", + "acq_rate = 0. # the detector acquisition rate, use 0 to try to auto-determine\n", "gain_setting = -1 # the gain setting, use -1 to use value stored in slow data.\n", "gain_mode = -1 # gain mode (0: adaptive, 1-3 fixed high/med/low, -1: read from CONTROL data)\n", + "overwrite = True # set to True if existing data should be overwritten\n", "max_pulses = [0, 352, 1] # range list [st, end, step] of memory cell indices to be processed within a train. 3 allowed maximum list input elements.\n", - "mem_cells_db = -1 # set to a value different than 0 to use this value for DB queries\n", + "mem_cells_db = 0 # set to a value different than 0 to use this value for DB queries\n", "integration_time = -1 # integration time, negative values for auto-detection.\n", "\n", "# Correction parameters\n", @@ -122,6 +123,7 @@ "outputs": [], "source": [ "import itertools\n", + "import os\n", "import math\n", "import multiprocessing\n", "import re\n", @@ -139,7 +141,7 @@ "import matplotlib\n", "import matplotlib.pyplot as plt\n", "import yaml\n", - "from extra_data import RunDirectory, stack_detector_data\n", + "from extra_data import H5File, RunDirectory, stack_detector_data, by_id\n", "from extra_geom import AGIPD_1MGeometry, AGIPD_500K2GGeometry\n", "from matplotlib import cm as colormap\n", "from matplotlib.colors import LogNorm\n", @@ -162,14 +164,11 @@ ")\n", "from cal_tools.ana_tools import get_range\n", "from cal_tools.enums import AgipdGainMode, BadPixels\n", - "from cal_tools.restful_config import restful_config\n", "from cal_tools.step_timing import StepTimer\n", - "from cal_tools.tools import (\n", - " CalibrationMetadata,\n", - " calcat_creation_time,\n", - " map_modules_from_folder,\n", - " module_index_to_qm,\n", - ")" + "\n", + "sns.set()\n", + "sns.set_context(\"paper\", font_scale=1.4)\n", + "sns.set_style(\"ticks\")" ] }, { @@ -283,7 +282,7 @@ "else:\n", " modules = [int(x[-2:]) for x in karabo_da]\n", "\n", - "print(\"Process modules:\", ', '.join(module_index_to_qm(x) for x in modules))\n", + "print(\"Process modules:\", ', '.join(cal_tools.tools.module_index_to_qm(x) for x in modules))\n", "print(f\"Detector in use is {karabo_id}\")\n", "print(f\"Instrument {instrument}\")\n", "print(f\"Detector instance {dinstance}\")" @@ -326,7 +325,7 @@ "outputs": [], "source": [ "# set everything up filewise\n", - "mapped_files, _, total_sequences, _, _ = map_modules_from_folder(\n", + "mapped_files, _, total_sequences, _, _ = cal_tools.tools.map_modules_from_folder(\n", " str(in_folder), run, path_template, karabo_da, sequences\n", ")\n", "file_list = []\n", @@ -376,21 +375,22 @@ "metadata": {}, "outputs": [], "source": [ - "# Run's creation time:\n", - "creation_time = calcat_creation_time(in_folder, run, creation_time)\n", - "offset = parser.parse(creation_date_offset)\n", - "delta = timedelta(hours=offset.hour, minutes=offset.minute, seconds=offset.second)\n", - "creation_time += delta\n", - "print(f\"Creation time: {creation_time}\")\n", - "\n", - "if acq_rate == -1.:\n", + "# Evaluate creation time\n", + "creation_time = None\n", + "if use_dir_creation_date:\n", + " creation_time = cal_tools.tools.get_dir_creation_date(str(in_folder), run)\n", + " offset = parser.parse(creation_date_offset)\n", + " delta = timedelta(hours=offset.hour, minutes=offset.minute, seconds=offset.second)\n", + " creation_time += delta\n", + "\n", + "if acq_rate == 0.:\n", " acq_rate = agipd_cond.get_acq_rate()\n", - "if mem_cells == -1:\n", + "if mem_cells == 0.:\n", " mem_cells = agipd_cond.get_num_cells()\n", "# TODO: look for alternative for passing creation_time\n", "if gain_setting == -1:\n", " gain_setting = agipd_cond.get_gain_setting(creation_time)\n", - "if bias_voltage == -1:\n", + "if bias_voltage == 0.:\n", " bias_voltage = agipd_cond.get_bias_voltage(karabo_id_control)\n", "if integration_time == -1:\n", " integration_time = agipd_cond.get_integration_time()\n", @@ -407,9 +407,9 @@ "outputs": [], "source": [ "if mem_cells is None:\n", - " raise ValueError(f\"No raw images found for {instrument_src_mod}\")\n", + " raise ValueError(f\"No raw images found in {filename}\")\n", "\n", - "mem_cells_db = mem_cells if mem_cells_db == -1 else mem_cells_db\n", + "mem_cells_db = mem_cells if mem_cells_db == 0 else mem_cells_db\n", "\n", "print(f\"Maximum memory cells to calibrate: {mem_cells}\")" ] @@ -551,37 +551,6 @@ "module_index_to_karabo_da = {mod: da for (mod, da) in zip(modules, karabo_da)}" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "metadata = CalibrationMetadata(metadata_folder or out_folder)\n", - "# NOTE: this notebook will not overwrite calibration metadata file\n", - "const_yaml = metadata.get(\"retrieved-constants\", {})" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Connect to CalCat.\n", - "calcat_config = restful_config['calcat']\n", - "client = CalibrationClient(\n", - " base_api_url=calcat_config['base-api-url'],\n", - " use_oauth2=calcat_config['use-oauth2'],\n", - " client_id=calcat_config['user-id'],\n", - " client_secret=calcat_config['user-secret'],\n", - " user_email=calcat_config['user-email'],\n", - " token_url=calcat_config['token-url'],\n", - " refresh_url=calcat_config['refresh-url'],\n", - " auth_url=calcat_config['auth-url'],\n", - " scope='')" - ] - }, { "cell_type": "code", "execution_count": null, @@ -601,6 +570,7 @@ "\n", " Metadata for constants is taken from yml file or retrieved from the DB\n", " \"\"\"\n", + " err = \"\"\n", " k_da = module_index_to_karabo_da[mod]\n", " # check if there is a yaml file in out_folder that has the device constants.\n", " if k_da in const_yaml:\n", @@ -638,50 +608,6 @@ "print(f\"Constants were loaded in {perf_counter()-ts:.01f}s\")" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# if the yml file contains \"retrieved-constants\", that means a leading\n", - "# notebook got processed and the reporting would be generated from it.\n", - "fst_print = True\n", - "timestamps = {}\n", - "\n", - "for i, (modno, when, k_da) in enumerate(const_out):\n", - " qm = module_index_to_qm(modno)\n", - "\n", - " if k_da not in const_yaml:\n", - " if fst_print:\n", - " print(\"Constants are retrieved with creation time: \")\n", - " fst_print = False\n", - "\n", - " module_timestamps = {}\n", - "\n", - " print(f\"{qm}:\")\n", - " for key, item in when.items():\n", - " if hasattr(item, 'strftime'):\n", - " item = item.strftime('%y-%m-%d %H:%M')\n", - " when[key] = item\n", - " print('{:.<12s}'.format(key), item)\n", - "\n", - " # Store few time stamps if exists\n", - " # Add NA to keep array structure\n", - " for key in ['Offset', 'SlopesPC', 'SlopesFF']:\n", - " if when and key in when and when[key]:\n", - " module_timestamps[key] = when[key]\n", - " else:\n", - " module_timestamps[key] = \"NA\"\n", - " timestamps[qm] = module_timestamps\n", - "\n", - "seq = sequences[0] if sequences else 0\n", - "\n", - "if timestamps:\n", - " with open(f\"{out_folder}/retrieved_constants_s{seq}.yml\",\"w\") as fd:\n", - " yaml.safe_dump({\"time-summary\": {f\"S{seq}\": timestamps}}, fd)" - ] - }, { "cell_type": "code", "execution_count": null, @@ -830,8 +756,11 @@ "fst_print = True\n", "timestamps = {}\n", "\n", - "for i, (modno, when, k_da) in enumerate(const_out):\n", - " qm = module_index_to_qm(modno)\n", + "for i, (error, modno, when, k_da) in enumerate(const_out):\n", + " qm = cal_tools.tools.module_index_to_qm(modno)\n", + " # expose errors while applying correction\n", + " if error:\n", + " print(\"Error: {}\".format(error) )\n", "\n", " if k_da not in const_yaml:\n", " if fst_print:\n", @@ -840,12 +769,14 @@ "\n", " module_timestamps = {}\n", "\n", - " print(f\"{qm}:\")\n", - " for key, item in when.items():\n", - " if hasattr(item, 'strftime'):\n", - " item = item.strftime('%y-%m-%d %H:%M')\n", - " when[key] = item\n", - " print('{:.<12s}'.format(key), item)\n", + " # If correction is crashed\n", + " if not error:\n", + " print(f\"{qm}:\")\n", + " for key, item in when.items():\n", + " if hasattr(item, 'strftime'):\n", + " item = item.strftime('%y-%m-%d %H:%M')\n", + " when[key] = item\n", + " print('{:.<12s}'.format(key), item)\n", "\n", " # Store few time stamps if exists\n", " # Add NA to keep array structure\n", @@ -853,7 +784,10 @@ " if when and key in when and when[key]:\n", " module_timestamps[key] = when[key]\n", " else:\n", - " module_timestamps[key] = \"NA\"\n", + " if error is not None:\n", + " module_timestamps[key] = \"Err\"\n", + " else:\n", + " module_timestamps[key] = \"NA\"\n", " timestamps[qm] = module_timestamps\n", "\n", "seq = sequences[0] if sequences else 0\n", diff --git a/notebooks/AGIPD/AGIPD_Retrieve_Constants_Precorrection.ipynb b/notebooks/AGIPD/AGIPD_Retrieve_Constants_Precorrection.ipynb index 62f64d8c5f14840681c6b0fff79d4ff2950ac819..4f155d4a8c82d35192fe855734d580ad065ff00b 100644 --- a/notebooks/AGIPD/AGIPD_Retrieve_Constants_Precorrection.ipynb +++ b/notebooks/AGIPD/AGIPD_Retrieve_Constants_Precorrection.ipynb @@ -20,25 +20,28 @@ "in_folder = \"/gpfs/exfel/exp/SPB/202030/p900119/raw\" # the folder to read data from, required\n", "out_folder = \"/gpfs/exfel/data/scratch/ahmedk/test/AGIPD_\" # the folder to output to, 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", "modules = [-1] # modules to correct, set to -1 for all, range allowed\n", "run = 80 # runs to process, required\n", "\n", "karabo_id = \"SPB_DET_AGIPD1M-1\" # karabo karabo_id\n", "karabo_da = ['-1'] # a list of data aggregators names, Default [-1] for selecting all data aggregators\n", + "path_template = 'RAW-R{:04d}-{}-S{:05d}.h5' # the template to use to access data\n", "ctrl_source_template = '{}/MDL/FPGA_COMP_TEST' # path to control information\n", "instrument_source_template = '{}/DET/{}:xtdf' # path in the HDF5 file to images\n", "receiver_template = \"{}CH0\" # inset for receiver devices\n", "karabo_id_control = \"SPB_IRU_AGIPD1M1\" # karabo-id for control device\n", "\n", - "# Parameters for calibration database.\n", + "use_dir_creation_date = True # use the creation data of the input dir for database queries\n", "cal_db_interface = \"tcp://max-exfl016:8015#8045\" # the database interface to use\n", "creation_date_offset = \"00:00:00\" # add an offset to creation date, e.g. to get different constants\n", - "creation_time = \"\" # To overwrite the measured creation_time. Required Format: YYYY-MM-DD HR:MN:SC e.g. \"2022-06-28 13:00:00\"\n", "\n", "slopes_ff_from_files = \"\" # Path to locally stored SlopesFF and BadPixelsFF constants\n", - "mem_cells = -1 # number of memory cells used, set to 0 to automatically infer\n", - "bias_voltage = -1 # bias voltage, set to 0 to use stored value in slow data.\n", - "acq_rate = -1. # the detector acquisition rate, use 0 to try to auto-determine\n", + "calfile = \"\" # path to calibration file. Leave empty if all data should come from DB\n", + "nodb = False # if set only file-based constants will be used\n", + "mem_cells = 0 # number of memory cells used, set to 0 to automatically infer\n", + "bias_voltage = 0 # bias voltage, set to 0 to use stored value in slow data.\n", + "acq_rate = 0. # the detector acquisition rate, use 0 to try to auto-determine\n", "gain_setting = -1 # the gain setting, use -1 to use value stored in slow data.\n", "gain_mode = -1 # gain mode (0: adaptive, 1-3 fixed high/med/low, -1: read from CONTROL data)\n", "integration_time = -1 # integration time, negative values for auto-detection.\n", @@ -50,6 +53,7 @@ "blc_noise = False # if set, baseline correction via noise peak location is attempted\n", "blc_stripes = False # if set, baseline corrected via stripes\n", "blc_hmatch = False # if set, base line correction via histogram matching is attempted\n", + "match_asics = False # if set, inner ASIC borders are matched to the same signal level\n", "adjust_mg_baseline = False # adjust medium gain baseline to match highest high gain value" ] }, @@ -86,7 +90,10 @@ "from pathlib import Path\n", "from typing import Tuple\n", "\n", + "import matplotlib\n", + "import matplotlib.pyplot as plt\n", "import multiprocessing\n", + "import numpy as np\n", "from datetime import timedelta\n", "from dateutil import parser\n", "from extra_data import RunDirectory\n", @@ -115,9 +122,7 @@ "# slopes_ff_from_files left as str for now\n", "in_folder = Path(in_folder)\n", "out_folder = Path(out_folder)\n", - "metadata = CalibrationMetadata(metadata_folder or out_folder)\n", - "# Constant paths & timestamps are saved under retrieved-constants in calibration_metadata.yml\n", - "retrieved_constants = metadata.setdefault(\"retrieved-constants\", {})" + "metadata = tools.CalibrationMetadata(metadata_folder or out_folder)" ] }, { @@ -126,17 +131,21 @@ "metadata": {}, "outputs": [], "source": [ - "# Run's creation time:\n", - "creation_time = calcat_creation_time(in_folder, run, creation_time)\n", - "offset = parser.parse(creation_date_offset)\n", - "delta = timedelta(hours=offset.hour, minutes=offset.minute, seconds=offset.second)\n", - "creation_time += delta\n", - "print(f\"Creation time: {creation_time}\")\n", + "creation_time = None\n", + "if use_dir_creation_date:\n", + " creation_time = tools.get_dir_creation_date(str(in_folder), run)\n", + " offset = parser.parse(creation_date_offset)\n", + " delta = timedelta(hours=offset.hour, minutes=offset.minute, seconds=offset.second)\n", + " creation_time += delta\n", + " print(f\"Using {creation_time} as creation time\")\n", + "\n", + "if sequences[0] == -1:\n", + " sequences = None\n", " \n", "print(f\"Outputting to {out_folder}\")\n", "out_folder.mkdir(parents=True, exist_ok=True)\n", "\n", - "melt_snow = False if corr_bools[\"only_offset\"] else SnowResolution.NONE" + "melt_snow = False if corr_bools[\"only_offset\"] else agipdlib.SnowResolution.NONE" ] }, { @@ -191,7 +200,7 @@ "metadata": {}, "outputs": [], "source": [ - "agipd_cond = AgipdCtrl(\n", + "agipd_cond = agipdlib.AgipdCtrl(\n", " run_dc=run_dc,\n", " image_src=None, # Not neededed, as we wont read mem_cells or acq_rate.\n", " ctrl_src=ctrl_src,\n", @@ -199,7 +208,7 @@ "\n", "if gain_setting == -1:\n", " gain_setting = agipd_cond.get_gain_setting(creation_time)\n", - "if bias_voltage == -1:\n", + "if bias_voltage == 0.:\n", " bias_voltage = agipd_cond.get_bias_voltage(karabo_id_control)\n", "if integration_time == -1:\n", " integration_time = agipd_cond.get_integration_time()\n", @@ -364,36 +373,39 @@ "metadata": {}, "outputs": [], "source": [ - "def find_cells_acq_rate_module(idx):\n", - " \"\"\"Find memory cells and acquisition rate for a module.\"\"\"\n", - " agipd_cond.image_src = instrument_src.format(idx)\n", - "\n", - " if agipd_cond.image_src not in instr_dc.all_sources:\n", - " warning(f\"No raw images found for {module_index_to_qm(idx)}({k_da}).\")\n", - " return None, None\n", - " \n", - " _mem_cells = agipd_cond.get_num_cells() if mem_cells == -1 else mem_cells\n", - " _acq_rate = agipd_cond.get_acq_rate() if acq_rate == -1 else acq_rate\n", - "\n", - " return _mem_cells, _acq_rate\n", - "\n", - "\n", - "all_mem_cells = set()\n", - "all_acq_rates = set()\n", + "# Constant paths & timestamps are saved under retrieved-constants in calibration_metadata.yml\n", + "retrieved_constants = metadata.setdefault(\"retrieved-constants\", {})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pc_bools = [corr_bools.get(\"rel_gain\"),\n", + " corr_bools.get(\"adjust_mg_baseline\"),\n", + " corr_bools.get('blc_noise'),\n", + " corr_bools.get('blc_hmatch'),\n", + " corr_bools.get('blc_stripes'),\n", + " melt_snow]\n", + "inp = []\n", + "only_dark = False\n", + "nodb_with_dark = False\n", + "if not nodb:\n", + " only_dark = (calfile != \"\")\n", + "if calfile != \"\" and not corr_bools[\"only_offset\"]:\n", + " nodb_with_dark = nodb\n", "\n", - "with multiprocessing.Pool(processes=nmods) as pool:\n", - " results = pool.map(find_cells_acq_rate_module, modules)\n", + "da_to_qm = dict()\n", + "for module_index, k_da in zip(modules, karabo_da):\n", + " da_to_qm[k_da] = tools.module_index_to_qm(module_index)\n", + " if k_da in retrieved_constants:\n", + " print(\n", + " f\"Constant for {k_da} already in calibration_metadata.yml, won't query again.\")\n", + " continue\n", "\n", - "for (_mem_cells, _acq_rate) in results:\n", - " all_mem_cells.add(_mem_cells)\n", - " all_acq_rates.add(_acq_rate)\n", - "# Validate that mem_cells and acq_rate are the same for all modules.\n", - "if len(all_mem_cells) != 1 or len(all_acq_rates) != 1:\n", - " warning(\n", - " \"Number of memory cells or acquisition rate are not identical for all modules.\\n\"\n", - " f\"different mem_cells values: {all_mem_cells}.\\ndifferent acq_rate values: {all_acq_rates}.\")\n", - "mem_cells = all_mem_cells.pop()\n", - "acq_rate = all_acq_rates.pop()" + " inp.append((k_da, module_index))" ] }, { @@ -466,25 +478,6 @@ "\n", "metadata.save()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(\"\\nRetrieved constants for modules:\",\n", - " ', '.join([module_index_to_qm(x) for x in modules]))\n", - "print(f\"Operating conditions are:\")\n", - "print(f\"• Bias voltage: {bias_voltage}\")\n", - "print(f\"• Memory cells: {mem_cells}\")\n", - "print(f\"• Acquisition rate: {acq_rate}\")\n", - "print(f\"• Gain mode: {gain_mode.name}\")\n", - "print(f\"• Gain setting: {gain_setting}\")\n", - "print(f\"• Integration time: {integration_time}\")\n", - "print(f\"• Photon Energy: 9.2\")\n", - "step_timer.done_step(f\"Constant metadata is saved under \\\"retrieved-constants\\\" in {metadata.filename}\")" - ] } ], "metadata": { diff --git a/src/cal_tools/agipdlib.py b/src/cal_tools/agipdlib.py index 13781f7cd78cfb9197bfbf0f5352d18aea735dc0..fe7e1079d9e4d278a6c1156411bead1397a9b0c5 100644 --- a/src/cal_tools/agipdlib.py +++ b/src/cal_tools/agipdlib.py @@ -2,19 +2,20 @@ import os import posixpath import zlib from datetime import datetime -from logging import warning from multiprocessing import Manager from multiprocessing.pool import ThreadPool -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Optional, Tuple import h5py import numpy as np import sharedmem from dateutil import parser from extra_data import DataCollection, H5File, by_id, components +from iCalibrationDB import Conditions, Constants from cal_tools import agipdalgs as calgs from cal_tools.agipdutils import ( + assemble_constant_dict, baseline_correct_via_noise, baseline_correct_via_stripe, correct_baseline_via_hist, @@ -26,6 +27,7 @@ from cal_tools.agipdutils import ( ) from cal_tools.enums import AgipdGainMode, BadPixels, SnowResolution from cal_tools.h5_copy_except import h5_copy_except_paths +from cal_tools.tools import get_from_db class AgipdCtrl: @@ -1337,12 +1339,12 @@ class AgipdCorrections: cons_data = dict() when = dict() variant = dict() - db_module = const_yaml[karabo_da]["physical-name"] + db_module = const_yaml[karabo_da]["physical-detector-unit"] for cname, mdata in const_yaml[karabo_da]["constants"].items(): base_key = f"{db_module}/{cname}/0" when[cname] = mdata["creation-time"] if when[cname]: - with h5py.File(mdata["path"], "r") as cf: + with h5py.File(mdata["file-path"], "r") as cf: cons_data[cname] = np.copy(cf[f"{base_key}/data"]) # Set variant to 0 if the attribute is missing # as for old constants. @@ -1352,43 +1354,54 @@ class AgipdCorrections: variant[cname] = 0 else: # Create empty constant using the list elements - cons_data[cname] = getattr(np, mdata["path"][0])(mdata["path"][1]) # noqa + cons_data[cname] = getattr(np, mdata["file-path"][0])(mdata["file-path"][1]) # noqa self.init_constants(cons_data, when, module_idx, variant) return when - def initialize_from_db( - self, karabo_id: str, - karabo_da: str, - module_idx: int, - creation_time: datetime, - memory_cells: int, - bias_voltage: int, - gain_setting: float, - gain_mode: int, - acquisition_rate: float, - integration_time: int, - photon_energy: float = 9.2, - client=None, - ): + def initialize_from_db(self, karabo_id: str, karabo_da: str, + cal_db_interface: str, + creation_time: datetime, + memory_cells: float, bias_voltage: int, + photon_energy: float, gain_setting: float, + acquisition_rate: float, integration_time: int, + module_idx: int, only_dark: bool = False): """ Initialize calibration constants from the calibration database - :param karabo_id: karabo detector identifier. - :param karabo_da: karabo module data aggregator name. - :param module_idx: module index to save retrieved CCV in sharedmem. - :param creation_time: time for desired calibration constant version. - :param memory_cells: number of memory cells used for CCV conditions. - :param bias_voltage: bias voltage used for CCV conditions. - :param gain_setting: gain setting used for CCV conditions. - :param gain_mode: gain mode used for CCV conditions. - :param acquisition_rate: acquistion rate used for CCV conditions. - :param integration_time: integration time used for CCV conditions. - :param photon_energy: photon energy value used for CCV conditions. - :param client: calibration_client object for CalibrationData objects. - - Loading the following constants based on the - correction configuration: + :param karabo_id: karabo identifier + :param karabo_da: karabo data aggregator + :param cal_db_interface: database interaface port + :param creation_time: time for desired calibration constant version + :param memory_cells: number of memory cells used for CCV conditions + :param bias_voltage: bias voltage used for CCV conditions + :param photon_energy: photon energy used for CCV conditions + :param gain_setting: gain setting used for CCV conditions + :param acquisition_rate: acquistion rate used for CCV conditions + :param integration_time: integration time used for CCV conditions + :param module_idx: module index to save retrieved CCV in sharedmem + :param only_dark: load only dark image derived constants. This + implies that a `calfile` is used to load the remaining + constants. Useful to reduce DB traffic and interactions + for non-frequently changing constants, i.e. such which are + not usually updated during a beamtime. + + The `cal_db_interface` parameter in the `dbparms` tuple may be in + one of the following notations: + * tcp://host:port to directly identify the host and port to + connect to + * tcp://host:port_low#port_high to specify a port range from + which a random port will be picked. E.g. specifying + + tcp://max-exfl016:8015#8025 + + will randomly pick an address in the range max-exfl016:8015 and + max-exfl016:8025. + + The latter notation allows for load-balancing. + + This routine loads the following constants as given in + `iCalibrationDB`: Dark Image Derived ------------------ @@ -1402,77 +1415,50 @@ class AgipdCorrections: ----------------------- * Constants.AGIPD.SlopesPC - * Constants.AGIPD.BadPixelsPC Flat-Field Derived * Constants.AGIPD.SlopesFF - * Constants.AGIPD.BadPixelsFF + """ - from cal_tools.calcat_interface import AGIPD_CalibrationData + + const_dict = assemble_constant_dict( + self.corr_bools, + self.pc_bools, + memory_cells, + bias_voltage, + gain_setting, + acquisition_rate, + photon_energy, + beam_energy=None, + only_dark=only_dark, + integration_time=integration_time + ) when = {} cons_data = {} variant = {} - agipd_cal = AGIPD_CalibrationData( - detector_name=karabo_id, - modules=[karabo_da], - sensor_bias_voltage=bias_voltage, - memory_cells=memory_cells, - acquisition_rate=acquisition_rate, - integration_time=integration_time, - source_energy=photon_energy, - gain_mode=gain_mode, - gain_setting=gain_setting, - event_at=creation_time, - client=client, - ) - - dark_constants = [ - "Offset", - "Noise", - "BadPixelsDark" - ] if self.gain_mode else [ - "ThresholdsDark", - "Offset", - "Noise", - "BadPixelsDark" - ] + for cname, cval in const_dict.items(): + condition = getattr( + Conditions, cval[2][0]).AGIPD(**cval[2][1]) + cdata, md = get_from_db( + karabo_id=karabo_id, + karabo_da=karabo_da, + constant=getattr(Constants.AGIPD, cname)(), + condition=condition, + empty_constant=getattr(np, cval[0])(cval[1]), + cal_db_interface=cal_db_interface, + creation_time=creation_time, + verbosity=0, + ) + cons_data[cname] = cdata + variant[cname] = md.calibration_constant_version.variant - gain_constants = [] - if any(self.pc_bools): - gain_constants += ["SlopesPC", "BadPixelsPC"] - if self.corr_bools.get("xray_corr"): - gain_constants += ["SlopesFF", "BadPixelsFF"] - - constants = dark_constants - constants += gain_constants - metadata = agipd_cal.metadata(constants) - # Validate the constants availability and raise/warn correspondingly. - for mod, ccv_dict in metadata.items(): - missing_dark_constants = set( - c for c in dark_constants if c not in ccv_dict.keys()) - missing_gain_constants = set( - c for c in gain_constants if c not in ccv_dict.keys()) - if missing_dark_constants: - raise KeyError( - f"Dark constants {missing_dark_constants} are not available" - f" for correction. Module: {mod}") - if missing_gain_constants: - warning( - f"Gain constants {missing_gain_constants} were" - f" not retrieved. Module: {mod}") - - for cname in constants: - if metadata[karabo_da].get(cname): - when[cname] = metadata[karabo_da][cname]["begin_validity_at"] - dataset = metadata[karabo_da][cname]["dataset"] - with h5py.File(agipd_cal.caldb_root / metadata[karabo_da][cname]["path"], "r") as cf: # noqa - cons_data[cname] = np.copy(cf[f"{dataset}/data"]) - variant[cname] = cf[dataset].attrs["variant"] if cf[dataset].attrs.keys() else 0 # noqa - else: - when[cname] = None + when[cname] = None + # Read the CCV begin at if constant was retrieved successfully. + if md and md.comm_db_success: + when[cname] = md.calibration_constant_version.begin_at self.init_constants(cons_data, when, module_idx, variant) diff --git a/tests/test_cal_tools.py b/tests/test_cal_tools.py index 55601886b3c3d9c719213f94fd45fe44b7f05b7e..ad493e46c1bf1cd15336508c9dbc98f296ae80af 100644 --- a/tests/test_cal_tools.py +++ b/tests/test_cal_tools.py @@ -9,7 +9,6 @@ from extra_data import open_run from iCalibrationDB import Conditions, ConstantMetaData, Constants from cal_tools.agipdlib import AgipdCorrections, CellRange -from cal_tools.calcat_interface import CalCatError from cal_tools.plotting import show_processed_modules from cal_tools.tools import ( creation_date_file_metadata, @@ -26,7 +25,6 @@ from cal_tools.tools import ( ACQ_RATE = 1.1 BIAS_VOLTAGE = 300 GAIN_SETTING = 0 -GAIN_MODE = 0 INTEGRATION_TIME = 12 MEM_CELLS = 352 PHOTON_ENERGY = 9.2 @@ -404,37 +402,6 @@ def test_get_pdu_from_db(_agipd_const_cond): "CAL_PHYSICAL_DETECTOR_UNIT-2_TEST"] -# TODO add a marker for accessing zmq end_point -@pytest.mark.requires_gpfs -@pytest.mark.requires_caldb -def test_raise_initialize_from_db(): - creation_time = datetime.strptime( - "2020-01-07 13:26:48.00", "%Y-%m-%d %H:%M:%S.%f") - - agipd_corr = AgipdCorrections( - max_cells=MEM_CELLS, - cell_sel=CellRange([0, 500, 1], MEM_CELLS)) - - agipd_corr.allocate_constants( - modules=[0], - constant_shape=(3, MEM_CELLS, 512, 128)) - - # CalCatError: calibration_constant_version not found ! - with pytest.raises(CalCatError): - agipd_corr.initialize_from_db( - karabo_id="TEST_DET_CAL_CI-1", - karabo_da="TEST_DET_CAL_DA1", - creation_time=creation_time, - memory_cells=MEM_CELLS, - bias_voltage=BIAS_VOLTAGE, - photon_energy=PHOTON_ENERGY, - gain_setting=GAIN_SETTING, - gain_mode=GAIN_MODE, - acquisition_rate=ACQ_RATE, - integration_time=INTEGRATION_TIME, - module_idx=0, - ) - # TODO add a marker for accessing zmq end_point @pytest.mark.requires_gpfs @pytest.mark.requires_caldb @@ -449,25 +416,45 @@ def test_initialize_from_db(): agipd_corr.allocate_constants( modules=[0], constant_shape=(3, MEM_CELLS, 512, 128)) - agipd_corr + dark_const_time_dict = agipd_corr.initialize_from_db( - karabo_id=AGIPD_KARABO_ID, - karabo_da="AGIPD00", + karabo_id="TEST_DET_CAL_CI-1", + karabo_da="TEST_DET_CAL_DA1", + cal_db_interface=CAL_DB_INTERFACE, creation_time=creation_time, memory_cells=MEM_CELLS, bias_voltage=BIAS_VOLTAGE, photon_energy=PHOTON_ENERGY, gain_setting=GAIN_SETTING, - gain_mode=GAIN_MODE, - integration_time=INTEGRATION_TIME, acquisition_rate=ACQ_RATE, + integration_time=INTEGRATION_TIME, module_idx=0, + only_dark=False, + ) + + assert dark_const_time_dict == { + "Offset": None, + "Noise": None, + "ThresholdsDark": None, + "BadPixelsDark": None, + } + + dark_const_time_dict = agipd_corr.initialize_from_db( + karabo_id=AGIPD_KARABO_ID, + karabo_da="AGIPD00", + cal_db_interface=CAL_DB_INTERFACE, + creation_time=creation_time, + memory_cells=MEM_CELLS, bias_voltage=BIAS_VOLTAGE, + photon_energy=PHOTON_ENERGY, gain_setting=GAIN_SETTING, + integration_time=INTEGRATION_TIME, + acquisition_rate=ACQ_RATE, module_idx=0, + only_dark=False, ) # A retrieved constant has a value of datetime creation_time - assert isinstance(dark_const_time_dict["Offset"], str) - assert set(dark_const_time_dict.keys()) == { - "Offset", "Noise", "ThresholdsDark", "BadPixelsDark"} + assert isinstance(dark_const_time_dict["Offset"], datetime) + assert list(dark_const_time_dict.keys()) == [ + "Offset", "Noise", "ThresholdsDark", "BadPixelsDark"] def test_module_index_to_qm():