Source code for dodal.devices.util.lookup_tables

"""
All the public methods in this module return a lookup table of some kind that
converts the source value s to a target value t for different values of s.
"""

from collections.abc import Callable, Sequence
from io import StringIO

import aiofiles
import numpy as np
from numpy import interp, loadtxt

from dodal.log import LOGGER


[docs] async def energy_distance_table(lookup_table_path: str) -> np.ndarray: """ Returns a numpy formatted lookup table for required positions of an ID gap to provide emission at a given beam energy. Args: lookup_table_path: Path to lookup table Returns: ndarray: Lookup table """ # Slight cheat to make the file IO async, numpy doesn't do any real IO now, just # decodes the text async with aiofiles.open(lookup_table_path) as stream: raw_table = await stream.read() return loadtxt(StringIO(raw_table), comments=["#", "Units"])
[docs] def parse_lookup_table(filename: str) -> list[Sequence]: """Parse a generic lookup table with a number of columns >= 2 and return a list \ in column major order of the values in it.""" LOGGER.info(f"Parsing lookup table file {filename}") lut_vals = zip(*loadtxt(filename, comments=["#", "Units"]), strict=False) return list(lut_vals)
[docs] def linear_interpolation_lut( s_values: Sequence, t_values: Sequence ) -> Callable[[float], float]: """Returns a callable that converts values by linear interpolation of lookup table values. If the value falls outside the lookup table then the closest value will be used.""" # numpy interp expects x-values to be increasing if not np.all(np.diff(s_values) > 0): LOGGER.info( "Configuration values in the lookup table are not ascending, trying reverse order..." ) s_values = list(reversed(s_values)) t_values = list(reversed(t_values)) if not np.all(np.diff(s_values) > 0): raise AssertionError( "Configuration lookup table does not monotonically increase or decrease." ) def s_to_t2(s: float) -> float: return float(interp(s, s_values, t_values)) return s_to_t2