"""Define functions to compute 1D longitudinal electric fields.
The ones used by :class:`.Field` will be in :file:`field_helpers.py` from now
on.
"""
import math
from collections.abc import Callable
from functools import partial
from typing import Any
import numpy as np
from lightwin.core.em_fields.types import FieldFuncComponent1D
[docs]
def null_field_1d(pos: Any) -> float:
"""Define a null electric/magnetic field."""
return 0.0
[docs]
def create_1d_field_func(
field_values: np.ndarray, corresponding_positions: np.ndarray
) -> Callable[[float], float]:
"""Create the function to get spatial component of electric field."""
func = partial(
_evaluate_1d_field,
field_values=field_values,
corresponding_positions=corresponding_positions,
)
return func
[docs]
def _evaluate_1d_field(
pos: float, field_values: np.ndarray, corresponding_positions: np.ndarray
) -> float:
"""Interpolate an electric/magnetic 1D field file."""
return float(
np.interp(
x=pos,
xp=corresponding_positions,
fp=field_values,
left=0.0,
right=0.0,
)
)
[docs]
def normalized_e_1d(
pos: float, e_func: Callable[[float], float], phi: float, phi_0: float
) -> float:
"""Compute electric field, normalized."""
return e_func(pos) * math.cos(phi + phi_0)
[docs]
def normalized_e_1d_complex(
pos: float, e_func: Callable[[float], float], phi: float, phi_0: float
) -> complex:
"""Compute electric field, normalized."""
return e_func(pos) * (math.cos(phi + phi_0) + 1j * math.sin(phi + phi_0))
[docs]
def e_1d(
pos: float,
e_func: Callable[[float], float],
phi: float,
amplitude: float,
phi_0: float,
) -> float:
"""Compute normed 1D electric field."""
return amplitude * normalized_e_1d(pos, e_func, phi, phi_0)
[docs]
def e_1d_complex(
pos: float,
e_func: Callable[[float], float],
phi: float,
amplitude: float,
phi_0: float,
) -> complex:
"""Compute normed 1D electric field."""
return amplitude * normalized_e_1d_complex(pos, e_func, phi, phi_0)
# def superpose_longitudinal_e_spats(
# e_spats: Collection[FieldFuncComponent1D], z_0s: Collection[float]
# ) -> list[FieldFuncComponent1D]:
# """Superpose the given electric fields.
#
# This is used by the ``SUPERPOSE_MAP`` command. We extend every electric
# field so that it spans over the whole range of positions, but electric
# fields are null outside of the range they were defined.
#
# """
# shifted_e_spats = [
# partial(shifted_e_spat, e_spat=e_spat, z_shift=z_0)
# for e_spat, z_0 in zip(e_spats, z_0s, strict=True)
# ]
# return shifted_e_spats
[docs]
def shifted_e_spat(
e_spat: FieldFuncComponent1D, z_shift: float, z_pos: float
) -> float:
"""Shift electric field by ``z_shift``."""
return e_spat(z_pos + z_shift)