Source code for giant.calibration.estimators.geometric.geometric_estimator


from dataclasses import dataclass

from typing import Optional, Protocol, runtime_checkable, Generic, TypeVar

from giant.camera_models import CameraModel
from giant._typing import DOUBLE_ARRAY

from giant.utilities.options import UserOptions
from giant.utilities.mixin_classes import AttributeEqualityComparison, AttributePrinting, UserOptionConfigured   


ModelT = TypeVar("ModelT", bound=CameraModel)
"""
Type variable bound to CameraModel for type safety
"""

[docs] @dataclass class GeometricEstimatorOptions(UserOptions): weighted_estimation: bool = False """ A boolean flag specifying whether to do weighted estimation. If set to ``True``, the estimator should use the provided measurement weights in :attr:`measurement_covariance` during the estimation process. If set to ``False``, then no measurement weights should be considered. """ a_priori_model_covariance: Optional[DOUBLE_ARRAY] = None """ A square numpy array containing the covariance matrix for the a priori estimate of the state vector. This is only considered if :attr:`weighted_estimation` is set to ``True`` and if :attr:`.CameraModel.use_a_priori` is set to ``True``, otherwise it is ignored. If both are set to ``True`` then this should be set to a square, full rank, lxl numpy array where ``l=len(model.state_vector)`` containing the covariance matrix for the a priori state vector. The order of the parameters in the state vector can be determined from :meth:`.CameraModel.get_state_labels`. """
[docs] @runtime_checkable class GeometricEstimator(Protocol, Generic[ModelT]): """ This protocol class serves as the template for implementing a class for doing geometric camera model estimation in GIANT. Camera model estimation in GIANT is primarily handled by the :class:`.Calibration` class, which does the steps of extracting observed stars in an image, pairing the observed stars with a star catalog, and then passing the observed star-catalog star pairs to a subclass of this protocol-class, which estimates an update to the camera model in place (the input camera model is modified, not a copy). In order for this to work, this protocol defines the minimum required interfaces that the :class:`.Calibration` class expects for an estimator. The required interface that the :class:`.Calibration` class expects consists of a few readable/writeable properties, and a couple of standard methods, as defined below. Beyond that the implementation is left to the user. If you are just doing a typical calibration, then you probably need not worry about this protocol and instead can use one of the 2 concrete classes defined in this package, which work well in nearly all cases. If you do have a need to implement your own estimator, then you should implement all the requirements in the protocol, and study the concrete classes from this subpackage for an example of what needs to be done. """ weighted_estimation: bool """ A boolean flag specifying whether to do weighted estimation. If set to ``True``, the estimator should use the provided measurement weights in :attr:`measurement_covariance` during the estimation process. If set to ``False``, then no measurement weights should be considered. """ a_priori_model_covariance: Optional[DOUBLE_ARRAY] """ A square numpy array containing the covariance matrix for the a priori estimate of the state vector. This is only considered if :attr:`weighted_estimation` is set to ``True`` and if :attr:`.CameraModel.use_a_priori` is set to ``True``, otherwise it is ignored. If both are set to ``True`` then this should be set to a square, full rank, lxl numpy array where ``l=len(model.state_vector)`` containing the covariance matrix for the a priori state vector. The order of the parameters in the state vector can be determined from :meth:`.CameraModel.get_state_labels`. """ def __init__(self, model: ModelT, options: GeometricEstimatorOptions | None) -> None: ... @property def model(self) -> ModelT: """ The camera model that is being estimated. Typically this should be a subclass of :class:`.CameraModel`. This should be a read/write property """ ... @model.setter def model(self, val: ModelT): # model must be writeable ... @property def successful(self) -> bool: """ A boolean flag indicating whether the fit was successful or not. If the fit was successful this should return ``True``, and ``False`` if otherwise. This should be a read-only property. """ ... @property def measurement_covariance(self) -> Optional[float | DOUBLE_ARRAY]: """ A square numpy array containing the covariance matrix for the measurements. If :attr:`weighted_estimation` is set to ``True`` then this property will contain the measurement covariance matrix as a square, full rank, numpy array. If :attr:`weighted_estimation` is set to ``False`` then this property may be ``None`` and should be ignored. This should be a read/write property. """ ... @measurement_covariance.setter def measurement_covariance(self, val: Optional[float | DOUBLE_ARRAY]): # measurement_covariance must be writeable ... @property def measurements(self) -> Optional[DOUBLE_ARRAY]: """ A 2xn numpy array of the observed pixel locations for stars across all images Each column of this array will correspond to the same column of the :attr:`camera_frame_directions` concatenated down the last axis. (That is ``measurements[:, i] <-> np.concatenate(camera_frame_directions, axis=-1)[:, i]``) This will always be set before a call to :meth:`estimate`. This should be a read/write property. """ ... @measurements.setter def measurements(self, val: DOUBLE_ARRAY): # measurements must be writeable ... @property def camera_frame_directions(self) -> list[DOUBLE_ARRAY | list[list]]: """ A length m list of unit vectors in the camera frame as numpy arrays for m images corresponding to the :attr:`measurements` attribute. Each element of this list corresponds to a unique image that is being considered for estimation and the subsequent element in the :attr:`temperatures` list. Each column of this concatenated array will correspond to the same column of the :attr:`measurements` array. (That is ``np.concatenate(camera_frame_directions, axis=-1)[:, i] <-> measurements[:, i]``). Any images for which no stars were identified (due to any number of reasons) will have a list of empty arrays in the corresponding element of this list (that is ``camera_frame_directions[i] == [[], [], []]`` where ``i`` is an image with no measurements identified). These will be automatically dropped by numpy's concatenate, but are included to notify the user which temperatures to use. This will always be set before a call to :meth:`estimate`. This should be a read/write property. """ ... @camera_frame_directions.setter def camera_frame_directions(self, val: list[DOUBLE_ARRAY | list[list]]): # camera_frame_directions must be writeable ... @property def temperatures(self) -> list[float]: """ A length m list of temperatures of the camera for each image being considered in estimation. Each element of this list corresponds to a unique image that is being considered for estimation and the subsequent element in the :attr:`camera_frame_directions` list. This will always be set before a call to :meth:`estimate` (although sometimes it may be a list of all zeros if temperature data is not available for the camera). This should be a read/write property. """ ... @temperatures.setter def temperatures(self, val: list[float]): # temperatures must be writeable ... @property def postfit_covariance(self) -> Optional[DOUBLE_ARRAY]: """ The post-fit state covariance matrix, taking into account the measurement covariance matrix (if applicable). This returns the post-fit state covariance matrix after a call to :meth:`estimate`. The covariance matrix will be in the order according to :attr:`~.CameraModel.estimation_parameters` and if :attr:`weighted_estimation` is ``True`` will return the state covariance matrix taking into account the measurement covariance matrix. If :attr:`weighted_estimation` is ``False``, then this will return the post-fit state covariance matrix assuming no measurement weighting (that is a measurement covariance matrix of the identity matrix). If :meth:`estimate` has not been called yet then this will return ``None`` This is a read only property """ ... @property def postfit_residuals(self) -> Optional[DOUBLE_ARRAY]: """ The post-fit observed-computed measurement residuals as a 2xn numpy array. This returns the post-fit observed minus computed measurement residuals after a call to :meth:`estimate`. If :meth:`estimate` has not been called yet then this will return ``None``. This is a read only property """ ... def estimate(self) -> None: """ Estimates an updated camera model that better transforms the camera frame directions into pixel locations to minimize the residuals between the observed and the predicted star locations. Typically, upon successful completion, the updated camera model is stored in the :attr:`model` attribute, the :attr:`successful` should return ``True``, and :attr:`postfit_residuals` and :attr:`postfit_covariance` should both be not None. If estimation is unsuccessful, then :attr:`successful` should be set to ``False`` and everything else will be ignored so you can do whatever you want with it. """ ... def reset(self) -> None: """ This method resets all of the data attributes to their default values to prepare for another estimation. This should reset * :attr:`successful` * :attr:`measurement_covariance` * :attr:`measurements` * :attr:`camera_frame_directions` * :attr:`temperatures` * :attr:`postfit_covariance` * :attr:`postfit_residuals` to their default values (typically ``None``) to ensure that data from one estimation doesn't get mixed with data from a subsequent estimation. You may also choose to reset some other attributes depending on the implementation of the estimator. """ ... def reset_settings(self) -> None: """ This method resets all the setting back to their original values as specified at instance creation. Generally this is provided for you through the :class:`.UserOptionConfigured` mixin class. """ ...
class GeometricEstimatorBC(UserOptionConfigured[GeometricEstimatorOptions], GeometricEstimatorOptions, AttributeEqualityComparison, AttributePrinting, GeometricEstimator[ModelT]): """ This base class is used to make it easy to make a GeometricEstimator class using other beneficial mixin classes from GIANT. Generally, therefore, custom classes should inherit from this, and not GeometricEstimator directly, though that's not strictly necessary """ pass