Source code for ewoksid24.math.xasmap
from typing import Callable
from typing import Tuple
import numpy
from ewoksfluo.math.regular_grid import ScatterDataInterpolator
from scipy.interpolate import interp1d
from ..io.xasmap import XasMapData
[docs]
class XasMapInterpolator:
def __init__(self, data: XasMapData) -> None:
self._energy_units = data.energy_units
if data.energy.ndim == 2:
self._energy_axis, self._mu = interpolate_energy(data)
elif data.energy.ndim == 1:
self._energy_axis = data.energy
self._mu = data.mu
else:
raise ValueError("energy field must be 1D or 2D")
self._interpolator = ScatterDataInterpolator(
[data.x0, data.x1],
[data.x0_name, data.x1_name],
[data.x0_units, data.x1_units],
)
@property
def energy_axis(self):
return self._energy_axis
@property
def energy_label(self) -> str:
name = "Energy"
units = self._energy_units
if units:
return f"{name} ({units})"
else:
return name
@property
def x0_axis(self) -> numpy.ndarray:
return self._interpolator.grid_axes[0]
@property
def x1_axis(self) -> numpy.ndarray:
return self._interpolator.grid_axes[1]
@property
def x0_axis_name(self) -> str:
return self._interpolator.axes_names[0]
@property
def x1_axis_name(self) -> str:
return self._interpolator.axes_names[1]
@property
def x0_axis_label(self) -> str:
return self._axis_label(0)
@property
def x1_axis_label(self) -> str:
return self._axis_label(1)
@property
def mu(self):
return self._mu
def _axis_label(self, i: int) -> str:
name = self._interpolator.axes_names[i]
units = self._interpolator.units
if units:
return f"{name} ({units})"
else:
return name
[docs]
def evaluate_as_map(
self, xas_func: Callable[[numpy.ndarray, numpy.ndarray], float]
) -> numpy.ndarray:
energy = self.energy_axis
values = numpy.array([xas_func(energy, mu) for mu in self._mu])
return self._interpolator.regrid(values)
[docs]
def get_single_point_mu(
self, pos_x0: float, pos_x1: float
) -> Tuple[float, float, numpy.ndarray]:
scatter0, scatter1 = self._interpolator.scatter_coordinates.T
distance = numpy.abs(scatter0 - pos_x0) + numpy.abs(scatter1 - pos_x1)
idx = numpy.argmin(distance)
return scatter0[idx], scatter1[idx], self._mu[idx]
[docs]
def interpolate_energy(data: XasMapData) -> Tuple[numpy.ndarray, numpy.ndarray]:
"""
Interpolates all mu spectra to a common energy axis.
:param data: Input XasMapData with possibly different energy axes per point.
:returns: Shared energy axis and interpolated mu.
"""
e0 = data.energy[:, 0].max()
e1 = data.energy[:, -1].min()
en = data.energy.shape[1]
energy = numpy.linspace(e0, e1, en)
mu_interp = numpy.empty((data.mu.shape[0], len(energy)))
for i in range(data.mu.shape[0]):
interp = interp1d(
data.energy[i], data.mu[i], bounds_error=False, fill_value=numpy.nan
)
mu_interp[i] = interp(energy)
return energy, mu_interp