diff --git a/notebooks/LPD/LPD_Correct_Fast.ipynb b/notebooks/LPD/LPD_Correct_Fast.ipynb index 184d6ce8689670217f7ca7e831804c14bceeea92..4fd91a297b48fe4f592193f0f5912462ae85d602 100644 --- a/notebooks/LPD/LPD_Correct_Fast.ipynb +++ b/notebooks/LPD/LPD_Correct_Fast.ipynb @@ -40,7 +40,7 @@ "creation_time = \"\" # The timestamp to use with Calibration DB. Required Format: \"YYYY-MM-DD hh:mm:ss\" e.g. 2019-07-04 11:02:41\n", "cal_db_interface = '' # Not needed, compatibility with current webservice.\n", "cal_db_timeout = 0 # Not needed, compatbility with current webservice.\n", - "cal_db_root = '/gpfs/exfel/d/cal/caldb_store'\n", + "cal_db_root = '/gpfs/exfel/d/cal/caldb_store' # The calibration database root path to access constant files. For example accessing constants from the test database.\n", "\n", "# Operating conditions\n", "mem_cells = 512 # Memory cells, LPD constants are always taken with 512 cells.\n", @@ -85,7 +85,6 @@ }, "outputs": [], "source": [ - "from collections import OrderedDict\n", "from logging import warning\n", "from pathlib import Path\n", "from time import perf_counter\n", @@ -100,19 +99,17 @@ "import matplotlib.pyplot as plt\n", "%matplotlib inline\n", "\n", - "from calibration_client import CalibrationClient\n", - "from calibration_client.modules import CalibrationConstantVersion\n", "import extra_data as xd\n", "import extra_geom as xg\n", "import pasha as psh\n", - "\n", "from extra_data.components import LPD1M\n", "\n", + "import cal_tools.restful_config as rest_cfg\n", + "from cal_tools.calcat_interface import CalCatError, LPD_CalibrationData\n", "from cal_tools.lpdalgs import correct_lpd_frames\n", "from cal_tools.lpdlib import get_mem_cell_pattern, make_cell_order_condition\n", "from cal_tools.tools import CalibrationMetadata, calcat_creation_time\n", - "from cal_tools.files import DataFile\n", - "from cal_tools.restful_config import restful_config" + "from cal_tools.files import DataFile" ] }, { @@ -136,19 +133,16 @@ "\n", "output_source = output_source or input_source\n", "\n", - "cal_db_root = Path(cal_db_root)\n", - "\n", - "metadata = CalibrationMetadata(metadata_folder or out_folder)\n", - "\n", "creation_time = calcat_creation_time(in_folder, run, creation_time)\n", "print(f'Using {creation_time.isoformat()} as creation time')\n", "\n", "# Pick all modules/aggregators or those selected.\n", - "if not karabo_da or karabo_da == ['']:\n", - " if not modules or modules == [-1]:\n", + "if karabo_da == ['']:\n", + " if modules == [-1]:\n", " modules = list(range(16))\n", - "\n", " karabo_da = [f'LPD{i:02d}' for i in modules]\n", + "else:\n", + " modules = [int(x[-2:]) for x in karabo_da]\n", " \n", "# Pick all sequences or those selected.\n", "if not sequences or sequences == [-1]:\n", @@ -236,26 +230,6 @@ "# Obtain and prepare calibration 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, @@ -270,41 +244,30 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "const_data = {}\n", - "const_load_mp = psh.ProcessContext(num_workers=24)\n", - "\n", - "if const_yaml: # Read constants from YAML file.\n", - " start = perf_counter()\n", - " for da, ccvs in const_yaml.items():\n", - "\n", - " for calibration_name, ccv in ccvs['constants'].items():\n", - " if ccv['file-path'] is None:\n", - " warning(f\"Missing {calibration_name} for {da}\")\n", - " continue\n", - "\n", - " dtype = np.uint32 if calibration_name.startswith('BadPixels') else np.float32\n", - "\n", - " const_data[(da, calibration_name)] = dict(\n", - " path=Path(ccv['file-path']),\n", - " dataset=ccv['dataset-name'],\n", - " data=const_load_mp.alloc(shape=(256, 256, mem_cells, 3), dtype=dtype)\n", + "const_data = dict() # {\"ModuleName\": {\"ConstantName\": ndarray}}\n", + "start = perf_counter()\n", + "if const_yaml:\n", + " const_load_mp = psh.ProcessContext(num_workers=24)\n", + "\n", + " for mod, constants in const_yaml.items():\n", + " const_data[mod] = {} # An empty dictionary stays for a module with no constants.\n", + " for cname, cmdata in constants[\"constants\"].items():\n", + " const_data[mod][cname] = const_load_mp.alloc(\n", + " shape=(256, 256, mem_cells, 3), # All LPD constants have the same shape.\n", + " dtype=np.uint32 if cname.startswith('BadPixels') else np.float32\n", " )\n", - "else: # Retrieve constants from CALCAT.\n", - " dark_calibrations = {\n", - " 1: 'Offset', # np.float32\n", - " 14: 'BadPixelsDark' # should be np.uint32, but is np.float64\n", - " }\n", - "\n", - " base_condition = [\n", - " dict(parameter_name='Sensor Bias Voltage', value=bias_voltage),\n", - " dict(parameter_name='Memory cells', value=mem_cells),\n", - " dict(parameter_name='Feedback capacitor', value=capacitor),\n", - " dict(parameter_name='Pixels X', value=256),\n", - " dict(parameter_name='Pixels Y', value=256),\n", - " ]\n", + " def load_constant_dataset(wid, index, mod):\n", + " for cname, mdata in const_yaml[mod][\"constants\"].items():\n", + " with h5py.File(mdata[\"path\"], \"r\") as cf:\n", + " cf[f\"{mdata['dataset']}/data\"].read_direct(const_data[mod][cname])\n", + "\n", + " const_load_mp.map(load_constant_dataset, karabo_da)\n", + "else:\n", " cell_ids_pattern_s = None\n", " if use_cell_order != 'never':\n", " # Read the order of memory cells used\n", @@ -313,57 +276,28 @@ " use_cell_order, get_mem_cell_pattern(raw_data, det_inp_sources)\n", " )\n", " print(\"Memory cells order:\", cell_ids_pattern_s)\n", - "\n", - " if cell_ids_pattern_s is not None:\n", - " dark_condition = base_condition + [\n", - " dict(parameter_name='Memory cell order', value=cell_ids_pattern_s),\n", - " ]\n", - " else:\n", - " dark_condition = base_condition.copy()\n", - "\n", - " illuminated_calibrations = {\n", - " 20: 'BadPixelsFF', # np.uint32\n", - " 42: 'GainAmpMap', # np.float32\n", - " 43: 'FFMap', # np.float32\n", - " 44: 'RelativeGain' # np.float32\n", - " }\n", - "\n", - " illuminated_condition = base_condition + [\n", - " dict(parameter_name='Source Energy', value=photon_energy),\n", - " dict(parameter_name='category', value=category)\n", - " ]\n", - "\n", - " print('Querying calibration database', end='', flush=True)\n", - " start = perf_counter()\n", - " for calibrations, condition in [\n", - " (dark_calibrations, dark_condition),\n", - " (illuminated_calibrations, illuminated_condition)\n", - " ]:\n", - " resp = CalibrationConstantVersion.get_closest_by_time_by_detector_conditions(\n", - " client, karabo_id, list(calibrations.keys()),\n", - " {'parameters_conditions_attributes': condition},\n", - " karabo_da='', event_at=creation_time.isoformat()\n", - " )\n", - "\n", - " if not resp['success']:\n", - " raise RuntimeError(resp)\n", - "\n", - " for ccv in resp['data']:\n", - " cc = ccv['calibration_constant']\n", - " da = ccv['physical_detector_unit']['karabo_da']\n", - " calibration_name = calibrations[cc['calibration_id']]\n", - " \n", - " dtype = np.uint32 if calibration_name.startswith('BadPixels') else np.float32\n", - " \n", - " const_data[(da, calibration_name)] = dict(\n", - " path=Path(ccv['path_to_file']) / ccv['file_name'],\n", - " dataset=ccv['data_set_name'],\n", - " data=const_load_mp.alloc(shape=(256, 256, mem_cells, 3), dtype=dtype)\n", - " )\n", - " print('.', end='', flush=True)\n", - " \n", + " lpd_cal = LPD_CalibrationData(\n", + " detector_name=karabo_id,\n", + " modules=karabo_da,\n", + " sensor_bias_voltage=bias_voltage,\n", + " memory_cells=mem_cells,\n", + " feedback_capacitor=capacitor,\n", + " source_energy=photon_energy,\n", + " memory_cell_order=cell_ids_pattern_s,\n", + " category=category,\n", + " event_at=creation_time,\n", + " client=rest_cfg.calibration_client(),\n", + " caldb_root=Path(cal_db_root),\n", + " )\n", + " const_data = lpd_cal.ndarray_map([\"Offset\", \"BadPixelsDark\"])\n", + " try:\n", + " illum_const_data = lpd_cal.ndarray_map(lpd_cal.illuminated_calibrations)\n", + " for key, value in illum_const_data.items():\n", + " const_data.setdefault(key, {}).update(value)\n", + " except CalCatError as e: # TODO: replace when API errors are improved.\n", + " warning(f\"CalCatError: {e}\")\n", "total_time = perf_counter() - start\n", - "print(f'{total_time:.1f}s')" + "print(f'Loading constants {total_time:.1f}s')" ] }, { @@ -372,20 +306,22 @@ "metadata": {}, "outputs": [], "source": [ - "def load_constant_dataset(wid, index, const_descr):\n", - " ccv_entry = const_data[const_descr]\n", - " \n", - " with h5py.File(cal_db_root / ccv_entry['path'], 'r') as fp:\n", - " fp[ccv_entry['dataset'] + '/data'].read_direct(ccv_entry['data'])\n", - " \n", - " print('.', end='', flush=True)\n", - "\n", - "print('Loading calibration data', end='', flush=True)\n", - "start = perf_counter()\n", - "const_load_mp.map(load_constant_dataset, list(const_data.keys()))\n", - "total_time = perf_counter() - start\n", - "\n", - "print(f'{total_time:.1f}s')" + "# Validate the constants availability and raise/warn accordingly.\n", + "for mod, calibrations in const_data.items():\n", + " missing_offset = {\"Offset\"} - set(calibrations)\n", + " warn_missing_constants = {\n", + " \"BadPixelsDark\", \"BadPixelsFF\", \"GainAmpMap\",\n", + " \"FFMap\", \"RelativeGain\"} - set(calibrations)\n", + " if missing_offset:\n", + " warning(f\"Offset constant is not available to correct {mod}.\")\n", + " karabo_da.remove(mod)\n", + " if warn_missing_constants:\n", + " warning(f\"Constants {warn_missing_constants} were not retrieved for {mod}.\")\n", + "if not karabo_da: # Offsets are missing for all modules.\n", + " raise Exception(\"Could not find offset constants for any modules, will not correct data.\")\n", + "\n", + "# Remove skipped correction modules from data_to_process\n", + "data_to_process = [(mod, in_f, out_f) for mod, in_f, out_f in data_to_process if mod in karabo_da]" ] }, { @@ -411,11 +347,7 @@ "}\n", "\n", "def prepare_constants(wid, index, aggregator):\n", - " consts = {calibration_name: entry['data']\n", - " for (aggregator_, calibration_name), entry\n", - " in const_data.items()\n", - " if aggregator == aggregator_}\n", - " \n", + " consts = const_data.get(aggregator, {})\n", " def _prepare_data(calibration_name, dtype):\n", " return consts[calibration_name] \\\n", " .transpose(constant_order[calibration_name]) \\\n", diff --git a/notebooks/LPD/LPD_retrieve_constants_precorrection.ipynb b/notebooks/LPD/LPD_retrieve_constants_precorrection.ipynb index 419a9a43f18cfbb5c1ded27e4adcba718cce0e39..27b78bc715629114466f4dd7e6e845c494cc3381 100644 --- a/notebooks/LPD/LPD_retrieve_constants_precorrection.ipynb +++ b/notebooks/LPD/LPD_retrieve_constants_precorrection.ipynb @@ -47,8 +47,8 @@ "metadata": {}, "outputs": [], "source": [ + "from logging import warning\n", "from pathlib import Path\n", - "from time import perf_counter\n", "\n", "import numpy as np\n", "\n", @@ -57,12 +57,13 @@ "import extra_data as xd\n", "\n", "from cal_tools.lpdlib import get_mem_cell_pattern, make_cell_order_condition\n", + "import cal_tools.restful_config as rest_cfg\n", + "from cal_tools.calcat_interface import CalCatError, LPD_CalibrationData\n", "from cal_tools.tools import (\n", " CalibrationMetadata,\n", " calcat_creation_time,\n", - " save_constant_metadata,\n", ")\n", - "from cal_tools.restful_config import restful_config" + "from cal_tools.step_timing import StepTimer" ] }, { @@ -87,6 +88,8 @@ " modules = list(range(16))\n", "\n", " karabo_da = [f'LPD{i:02d}' for i in modules]\n", + "else:\n", + " modules = [int(x[-2:]) for x in karabo_da]\n", "\n", "# List of detector sources.\n", "det_inp_sources = [input_source.format(karabo_id=karabo_id, module_index=int(da[-2:])) for da in karabo_da]" @@ -98,18 +101,7 @@ "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='')" + "step_timer = StepTimer()" ] }, { @@ -118,18 +110,8 @@ "metadata": {}, "outputs": [], "source": [ - "dark_calibrations = {\n", - " 1: 'Offset',\n", - " 14: 'BadPixelsDark',\n", - "}\n", - "\n", - "base_condition = [\n", - " dict(parameter_name='Sensor Bias Voltage', value=bias_voltage),\n", - " dict(parameter_name='Memory cells', value=mem_cells),\n", - " dict(parameter_name='Feedback capacitor', value=capacitor),\n", - " dict(parameter_name='Pixels X', value=256),\n", - " dict(parameter_name='Pixels Y', value=256),\n", - "]\n", + "step_timer.start()\n", + "\n", "cell_ids_pattern_s = None\n", "if use_cell_order != 'never':\n", " # Read the order of memory cells used\n", @@ -139,77 +121,57 @@ " )\n", " print(\"Memory cells order:\", cell_ids_pattern_s)\n", "\n", - "if cell_ids_pattern_s is not None:\n", - " dark_condition = base_condition + [\n", - " dict(parameter_name='Memory cell order', value=cell_ids_pattern_s),\n", - " ]\n", - "else:\n", - " dark_condition = base_condition.copy()\n", - "\n", - "illuminated_calibrations = {\n", - " 20: 'BadPixelsFF',\n", - " 42: 'GainAmpMap',\n", - " 43: 'FFMap',\n", - " 44: 'RelativeGain',\n", - "}\n", - "\n", - "illuminated_condition = base_condition + [\n", - " dict(parameter_name='Source Energy', value=photon_energy),\n", - " dict(parameter_name='category', value=category)\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "const_data = {}\n", - "\n", - "print('Querying calibration database', end='', flush=True)\n", - "start = perf_counter()\n", - "for k_da in karabo_da:\n", - " pdu = None\n", - " retrieved_constants[k_da] = dict()\n", - " const_mdata = retrieved_constants[k_da][\"constants\"] = dict()\n", - " for calibrations, condition in [\n", - " (dark_calibrations, dark_condition),\n", - " (illuminated_calibrations, illuminated_condition)\n", - " ]:\n", - " resp = CalibrationConstantVersion.get_closest_by_time_by_detector_conditions(\n", - " client, karabo_id, list(calibrations.keys()),\n", - " {'parameters_conditions_attributes': condition},\n", - " karabo_da=k_da, event_at=creation_time.isoformat())\n", - "\n", - " if not resp[\"success\"]:\n", - " print(f\"ERROR: Constants {list(calibrations.values())} \"\n", - " f\"were not retrieved, {resp['app_info']}\")\n", - " for cname in calibrations.values():\n", - " if cname == 'Offset':\n", - " raise Exception(\"Could not find offset constant, will not correct data\")\n", - " const_mdata[cname] = dict()\n", - " const_mdata[cname][\"file-path\"] = None\n", - " const_mdata[cname][\"dataset-name\"] = None\n", - " const_mdata[cname][\"creation-time\"] = None \n", - " continue\n", - "\n", - " for ccv in resp[\"data\"]:\n", - " cc = ccv['calibration_constant']\n", - " cname = calibrations[cc['calibration_id']]\n", - " const_mdata[cname] = dict()\n", - " const_mdata[cname][\"file-path\"] = str(Path(ccv['path_to_file']) / ccv['file_name'])\n", - " const_mdata[cname][\"dataset-name\"] = ccv['data_set_name']\n", - " const_mdata[cname][\"creation-time\"] = ccv['begin_at']\n", - " pdu = ccv['physical_detector_unit']['physical_name']\n", - "\n", - " print('.', end='', flush=True)\n", - " retrieved_constants[k_da][\"physical-detector-unit\"] = pdu\n", + "lpd_cal = LPD_CalibrationData(\n", + " detector_name=karabo_id,\n", + " modules=karabo_da,\n", + " sensor_bias_voltage=bias_voltage,\n", + " memory_cells=mem_cells,\n", + " feedback_capacitor=capacitor,\n", + " source_energy=photon_energy,\n", + " memory_cell_order=cell_ids_pattern_s,\n", + " category=category,\n", + " event_at=creation_time,\n", + " client=rest_cfg.calibration_client(),\n", + ")\n", + "\n", + "# Initialize const_data in case no constants were retrieved.\n", + "lpd_cal_metadata = {mod: {\"no-constants-retrieved\": None} for mod in karabo_da}\n", + "\n", + "constant_data = lpd_cal.metadata([\"Offset\", \"BadPixelsDark\"])\n", + "try:\n", + " illum_const_data = lpd_cal.metadata(lpd_cal.illuminated_calibrations)\n", + " for key, value in illum_const_data.items():\n", + " const_data.setdefault(key, {}).update(value)\n", + "except CalCatError as e: # TODO: replace when API errors are improved.\n", + " warning(f\"CalCatError: {e}\")\n", + "\n", + "# Validate the constants availability and raise/warn correspondingly. \n", + "for mod, ccv_dict in lpd_cal_metadata.items():\n", + " missing_offset = {\"Offset\"} - set(ccv_dict)\n", + " warn_missing_constants = {\n", + " \"BadPixelsDark\", \"BadPixelsFF\", \"GainAmpMap\", \"FFMap\", \"RelativeGain\"} - set(ccv_dict)\n", + " if missing_offset:\n", + " warning(f\"Offset constant is not available to correct {mod}\")\n", + " karabo_da.remove(mod)\n", + " if warn_missing_constants:\n", + " warning(f\"Constants {warn_missing_constants} were not retrieved for {mod}.\")\n", + "if not karabo_da: # Offsets are missing for all modules.\n", + " raise Exception(\"Could not find offset constants for all modules, will not correct data.\")\n", + "\n", + "for mod, ccv_dict in lpd_cal_metadata.items():\n", + " mdata_dict = {\"constants\": dict()}\n", + " for cname, ccv_metadata in ccv_dict.items():\n", + " mdata_dict[\"constants\"][cname] = {\n", + " \"path\": str(lpd_cal.caldb_root / ccv_metadata[\"path\"]),\n", + " \"dataset\": ccv_metadata[\"dataset\"],\n", + " \"creation-time\": ccv_metadata[\"begin_validity_at\"],\n", + " \"ccv_id\": ccv_metadata[\"ccv_id\"],\n", + " }\n", + " mdata_dict[\"physical-name\"] = ccv_metadata[\"physical_name\"]\n", + " retrieved_constants[mod] = mdata_dict\n", "metadata.save()\n", "\n", - "total_time = perf_counter() - start\n", - "print(f'{total_time:.1f}s')\n", - "print(f\"Stored retrieved constants in {metadata.filename}\")" + "step_timer.done_step(f\"Stored retrieved constants in {metadata.filename}.\")" ] } ], diff --git a/src/cal_tools/calcat_interface.py b/src/cal_tools/calcat_interface.py index 1ad313f0a97f51ed2fc9f2b4e8eacb36a7d96598..bca8e5a3f08f75050537aac0d89c8e165bf373c4 100644 --- a/src/cal_tools/calcat_interface.py +++ b/src/cal_tools/calcat_interface.py @@ -1001,8 +1001,18 @@ class LPD_CalibrationData(SplitConditionCalibrationData): "Pixels X", "Pixels Y", "Feedback capacitor", + "Memory cell order", + ] + + illuminated_parameters = [ + "Sensor Bias Voltage", + "Memory cells", + "Pixels X", + "Pixels Y", + "Feedback capacitor", + "Source Energy", + "category" ] - illuminated_parameters = dark_parameters + ["Source Energy", "category"] def __init__( self, @@ -1013,6 +1023,7 @@ class LPD_CalibrationData(SplitConditionCalibrationData): pixels_x=256, pixels_y=256, source_energy=9.2, + memory_cell_order=None, category=1, modules=None, client=None, @@ -1034,6 +1045,7 @@ class LPD_CalibrationData(SplitConditionCalibrationData): self.pixels_x = pixels_x self.pixels_y = pixels_y self.feedback_capacitor = feedback_capacitor + self.memory_cell_order = memory_cell_order self.source_energy = source_energy self.category = category