diff --git a/notebooks/AGIPD/AGIPD_Correct_and_Verify.ipynb b/notebooks/AGIPD/AGIPD_Correct_and_Verify.ipynb index 49bbda86a0f183555114769a7f9167df77f913f1..9a2da6a73ab0a5cf6a0f62143cfaae6fcd047d51 100644 --- a/notebooks/AGIPD/AGIPD_Correct_and_Verify.ipynb +++ b/notebooks/AGIPD/AGIPD_Correct_and_Verify.ipynb @@ -137,6 +137,7 @@ "import math\n", "import multiprocessing\n", "import os\n", + "import sys\n", "import warnings\n", "from datetime import timedelta\n", "from logging import warning\n", @@ -182,6 +183,7 @@ "from cal_tools.step_timing import StepTimer\n", "from cal_tools.tools import (\n", " calcat_creation_time,\n", + " latex_warning,\n", " map_modules_from_folder,\n", " module_index_to_qm,\n", " write_constants_fragment,\n", @@ -326,6 +328,29 @@ "print(f\"Instrument {instrument}\")" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "train_available = False\n", + "\n", + "for m in modules:\n", + " try:\n", + " # Attempt to select the module. If no trains are available, ValueError might be raised\n", + " if len(dc[instrument_src.format(m), 'image.data'].drop_empty_trains().train_ids) > 0:\n", + " train_available = True\n", + " break # Found a module with available trains.\n", + " except ValueError as e:\n", + " warning(f\"Missing module {m} from data: {e}\")\n", + "\n", + "if not train_available:\n", + " # Execute this block if no modules with trains were found.\n", + " latex_warning(\"No trains available to correct for selected modules.\")\n", + " sys.exit(0)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -519,15 +544,21 @@ " get_data = {'auto': litfrm.read_or_process, 'offline': litfrm.process, 'online': litfrm.read}\n", " r = get_data[use_litframe_finder]()\n", " cell_sel = LitFrameSelection(r, train_ids, max_pulses, energy_threshold, use_super_selection)\n", + " print(f\"{cell_sel.msg()}\\n\")\n", " cell_sel.print_report()\n", + " if np.count_nonzero(r.nLitFrame.value) == 0: # No lit frames.\n", + " latex_warning(\n", + " \"No lit frames identified using AGIPD LitFrameFinder.\"\n", + " \" Offline correction will not be performed.\")\n", + " sys.exit(0)\n", " except LitFrameFinderError as err:\n", + " print(cell_sel.msg())\n", " warning(f\"Cannot use AgipdLitFrameFinder due to:\\n{err}\")\n", " cell_sel = CellRange(max_pulses, max_cells=mem_cells)\n", "else:\n", " # Use range selection\n", " cell_sel = CellRange(max_pulses, max_cells=mem_cells)\n", - "\n", - "print(cell_sel.msg())" + " print(cell_sel.msg())" ] }, { @@ -881,8 +912,6 @@ "\n", " Yields (file data slot, start index, stop index)\n", " \"\"\"\n", - " \n", - " \n", " for i_proc, n_img in enumerate(img_counts):\n", " n_chunks = math.ceil(n_img / chunk_size)\n", " for i in range(n_chunks):\n", @@ -896,6 +925,7 @@ "outputs": [], "source": [ "step_timer.start()\n", + "all_imgs_counts = []\n", "if max_tasks_per_worker == -1:\n", " max_tasks_per_worker = None\n", "with multiprocessing.Pool(maxtasksperchild=max_tasks_per_worker) as pool:\n", @@ -911,7 +941,8 @@ " )\n", " step_timer.done_step(f'Loading data from files')\n", "\n", - " if img_counts == 0:\n", + " all_imgs_counts += img_counts\n", + " if not np.any(img_counts):\n", " # Skip any further processing and output if there are no images to\n", " # correct in this file.\n", " continue\n", @@ -984,8 +1015,10 @@ "outputs": [], "source": [ "if skip_plots:\n", - " print('Skipping plots')\n", - " import sys\n", + " print(\"Skipping plots as configured.\")\n", + " sys.exit(0)\n", + "elif not np.any(all_imgs_counts):\n", + " latex_warning(f\"All sequence files contain no data for correction.\")\n", " sys.exit(0)" ] }, @@ -1030,7 +1063,6 @@ " run_data = RunDirectory(data_folder, include)\n", " except FileNotFoundError:\n", " warning(f'No corrected files for {include}. Skipping plots.')\n", - " import sys\n", " sys.exit(0)\n", " if tid is not None:\n", " tid, data = run_data.select(\n", diff --git a/notebooks/test/test-cli.ipynb b/notebooks/test/test-cli.ipynb index daacfb22315d6a9edadd4991c31937751e721e74..3636da9d1da1bed89988f4a7f15d027f04d22001 100644 --- a/notebooks/test/test-cli.ipynb +++ b/notebooks/test/test-cli.ipynb @@ -43,7 +43,9 @@ "metadata": {}, "outputs": [], "source": [ - "from pathlib import Path" + "from pathlib import Path\n", + "\n", + "from cal_tools.tools import latex_warning" ] }, { @@ -72,6 +74,28 @@ "source": [ "print(\"🥼\")" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Test `latex_warning` output which uses a custom `warningbox` latex command" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "latex_warning(\"This is a warning test message.\")\n", + "\n", + "# empty message\n", + "latex_warning(\"\")\n", + "\n", + "# special characters\n", + "latex_warning(\"$x < y$\")" + ] } ], "metadata": { diff --git a/src/cal_tools/agipdlib.py b/src/cal_tools/agipdlib.py index 66128cc39383201018b9be85e3e141f9416c40ff..cacbfde83b069758e304c3486e180e9a26d0dae8 100644 --- a/src/cal_tools/agipdlib.py +++ b/src/cal_tools/agipdlib.py @@ -1719,11 +1719,13 @@ class LitFrameSelection(CellSelection): t0, tN, st = (rec['train_range'] + (1,))[:3] ntrain = max((int(tN) - int(t0)) // int(st), 1) trsintf = ':'.join([str(n) for n in rec['train_range']]) - print(("{pattern_no:2d} {trsintf:25s} {ntrain:5d} " - "{nmissed_trains:4d} {npulse_exposed:4d} {ndataframe:3d} " - "{nframe_total:3d} [{frmintf}]" - ).format(frmintf=frmintf, ntrain=ntrain, - trsintf=trsintf, **rec)) + frmintf_display = f"[{frmintf}]" if frmintf else "No lit frames to correct!" + print( + f"{rec['pattern_no']:2d} {trsintf:25s} {ntrain:5d} " + f"{rec['nmissed_trains']:4d} {rec['npulse_exposed']:4d} " + f"{rec['ndataframe']:3d} {rec['nframe_total']:3d} " + f"{frmintf_display}" + ) if nrec > max_lines: print(f"... {nrec - max_lines + 1} more lines skipped") diff --git a/src/cal_tools/tools.py b/src/cal_tools/tools.py index 81be77efff25b2b34e54142f764373af14689ca8..0161fb8922db89a638ac1c8e70ca27e88da2882d 100644 --- a/src/cal_tools/tools.py +++ b/src/cal_tools/tools.py @@ -3,6 +3,7 @@ import json import os import re import zlib +from IPython.display import Latex, display from collections import OrderedDict from glob import glob from multiprocessing.pool import ThreadPool @@ -21,7 +22,7 @@ import numpy as np import requests import yaml import zmq -from extra_data import H5File, RunDirectory +from extra_data import H5File, PropertyNameError, RunDirectory from iCalibrationDB import ConstantMetaData, Versions from jupyter_server.serverapp import list_running_servers @@ -1151,3 +1152,9 @@ def exit_notebook(message): import sys print(message) sys.exit(0) + + +def latex_warning(message): + """Show latex warning custom command parsed correctly + when reports are generated.""" + display(Latex("\warningbox{" + message + "}")) diff --git a/src/xfel_calibrate/finalize.py b/src/xfel_calibrate/finalize.py index 82f6235c8afa9c03ed165f776092dbe83f8258cd..c2c46b513dc150dbc98a9495de2a2fd11ee9c0d4 100644 --- a/src/xfel_calibrate/finalize.py +++ b/src/xfel_calibrate/finalize.py @@ -245,6 +245,19 @@ def make_report(run_path: Path, cal_work_dir: Path, project: str, latex_elements = {'extraclassoptions': ',openany, oneside', 'preamble': r'\usepackage{longtable}', 'maketitle': r'\input{titlepage.tex.txt}'} + + # Define a new LaTeX command for warning boxes within the preamble + custom_latex_preamble = r''' + \newcommand{\warningbox}[1]{% + \noindent\fcolorbox{orange}{yellow}{% + \parbox{\textwidth}{% + \textbf{Warning:} #1% + }% + } + } + ''' + + latex_elements['preamble'] += custom_latex_preamble mf.write("latex_elements = {}\n".format(latex_elements)) mf.write("latex_logo = '{}/{}'\n".format(module_path, logo_path))