fit_distortion#

esis.optics.fit_distortion(instrument, scene, observation, bounds, parameters=None, pupil=None, axis_wavelength=None, axis_field=None, axis_channel=None, weight_correlation=1000, directory=None, kwargs_optimizer=None)[source]#

Fit the distortion parameters of an instrument to an observed image.

Wraps scipy.optimize.differential_evolution() around a DistortionObjective: the given parameters are flattened with named_arrays.pack() to seed the optimizer, the bounds are flattened the same way, and the best solution found is unpacked back into a DistortionParameters, which can be applied to the instrument with DistortionParameters.to_instrument().

Parameters:
  • instrument (AbstractInstrument) – The instrument model to fit, usually reduced to a single channel.

  • scene (FunctionArray) – The spectral radiance of the scene as a function of wavelength and field position, imaged through the instrument on every evaluation.

  • observation (AbstractScalar) – The observed image that the modeled images are compared against. Any axes of the modeled image which are not present in this array are summed over before comparing.

  • bounds (tuple[DistortionParameters, DistortionParameters]) – The lower and upper bounds of the fit, expressed in the same units as parameters.

  • parameters (None | DistortionParameters) – The initial guess of the fit, which also defines the units and structure of the parameter vector seen by the optimizer. If None, the current parameters of instrument are used.

  • pupil (None | AbstractCartesian2dVectorArray) – The vertices of the pupil grid used to image the scene.

  • axis_wavelength (None | str) – The logical axis of the scene corresponding to changing wavelength.

  • axis_field (None | tuple[str, str]) – The logical axes of the scene corresponding to changing field position.

  • axis_channel (None | str) – The logical axis of the observation corresponding to changing camera channel, used to compare each channel independently when fitting several channels at once with shared parameters. See DistortionObjective.axis_channel.

  • weight_correlation (float) – The weight of the correlation term of the objective relative to its off-target distance penalty.

  • directory (None | Path) – A directory where the convergence history is logged using a ConvergenceLogger. If None, the fit is not logged.

  • kwargs_optimizer (None | dict[str, Any]) – Additional keyword arguments passed to scipy.optimize.differential_evolution(), for example dict(workers=-1, popsize=40).

Return type:

DistortionParameters

Examples

Fit each channel of the ESIS flight-1 design to the Level-1 frame that esis.flights.f1.optics.distortion_fit() was optimized against.

import pathlib
import named_arrays as na
import esis

obs = esis.flights.f1.data.level_1()[dict(time=15)]
scene = esis.flights.f1.data.synth.scene_aia()[dict(time=15)]

instrument = esis.flights.f1.optics.design(num_distribution=0)

for i in range(obs.shape[instrument.axis_channel]):
    channel = instrument[dict(channel=i)]
    parameters = esis.optics.DistortionParameters.from_instrument(channel)

    # the scene's wavelength coordinate varies within each spectral
    # line along "velocity"; its per-line axis ("wavelength") is
    # absent from the observation and therefore summed over
    fitted = esis.optics.fit_distortion(
        instrument=channel,
        scene=scene,
        observation=obs.outputs[dict(channel=i)].value,
        bounds=esis.flights.f1.optics.distortion_fit_bounds(parameters),
        parameters=parameters,
        axis_wavelength="velocity",
        axis_field=("detector_x", "detector_y"),
        directory=pathlib.Path(f"distortion_fit/channel_{i}"),
        kwargs_optimizer=dict(workers=-1, popsize=40),
    )

    model = fitted.to_instrument(channel)