Source code for asdf_astropy.converters.transform.polynomial

import numpy as np
from packaging.version import parse as parse_version

from asdf_astropy.converters.helpers import parse_tag_version

from .core import TransformConverterBase


[docs] class PolynomialConverter(TransformConverterBase): """ ASDF support for serializing the 1D and 2D polynomial models. """ # Schema versions prior to 1.2 included an unrelated "domain" # property. We can't serialize the new domain values with those # versions because they don't validate. _DOMAIN_WINDOW_MIN_VERSION = parse_version("1.2.0") tags = ("tag:stsci.edu:asdf/transform/polynomial-*",) types = ( "astropy.modeling.polynomial.Polynomial1D", "astropy.modeling.polynomial.Polynomial2D", )
[docs] def to_yaml_tree_transform(self, model, tag, ctx): from astropy.modeling.polynomial import Polynomial1D, Polynomial2D if isinstance(model, Polynomial1D): coefficients = np.array(model.parameters) elif isinstance(model, Polynomial2D): degree = model.degree coefficients = np.zeros((degree + 1, degree + 1)) for i in range(degree + 1): for j in range(degree + 1): if i + j < degree + 1: name = "c" + str(i) + "_" + str(j) coefficients[i, j] = getattr(model, name).value node = {"coefficients": coefficients} if parse_tag_version(tag) >= self._DOMAIN_WINDOW_MIN_VERSION: if model.n_inputs == 1: if model.domain is not None: node["domain"] = model.domain if model.window is not None: node["window"] = model.window else: if model.x_domain or model.y_domain is not None: node["domain"] = (model.x_domain, model.y_domain) if model.x_window or model.y_window is not None: node["window"] = (model.x_window, model.y_window) return node
[docs] def from_yaml_tree_transform(self, node, tag, ctx): from astropy.modeling.polynomial import Polynomial1D, Polynomial2D coefficients = np.asarray(node["coefficients"]) n_dim = coefficients.ndim if n_dim == 1: domain = node.get("domain", None) window = node.get("window", None) model = Polynomial1D(coefficients.size - 1, domain=domain, window=window) model.parameters = coefficients elif n_dim == 2: # noqa: PLR2004 x_domain, y_domain = tuple(node.get("domain", (None, None))) x_window, y_window = tuple(node.get("window", (None, None))) shape = coefficients.shape degree = shape[0] - 1 if shape[0] != shape[1]: msg = "Coefficients must be an (n+1, n+1) matrix" raise TypeError(msg) coeffs = {} for i in range(shape[0]): for j in range(shape[0]): if i + j < degree + 1: name = "c" + str(i) + "_" + str(j) coeffs[name] = coefficients[i, j] model = Polynomial2D( degree, x_domain=x_domain, y_domain=y_domain, x_window=x_window, y_window=y_window, **coeffs, ) else: msg = "astropy supports only 1D or 2D polynomial models" raise NotImplementedError(msg) return model
_CLASS_NAME_TO_POLY_INFO = { "Legendre1D": ("legendre", 1), "Legendre2D": ("legendre", 2), "Chebyshev1D": ("chebyshev", 1), "Chebyshev2D": ("chebyshev", 2), "Hermite1D": ("hermite", 1), "Hermite2D": ("hermite", 2), } _POLY_INFO_TO_CLASS_NAME = {v: k for k, v in _CLASS_NAME_TO_POLY_INFO.items()}
[docs] class OrthoPolynomialConverter(TransformConverterBase): """ ASDF support for serializing models that inherit OrthoPolyomialBase. """ # Map of model class name to (polynomial type, number of dimensions) tuple: tags = ("tag:stsci.edu:asdf/transform/ortho_polynomial-*",) types = ( "astropy.modeling.polynomial.Legendre1D", "astropy.modeling.polynomial.Legendre2D", "astropy.modeling.polynomial.Chebyshev1D", "astropy.modeling.polynomial.Chebyshev2D", "astropy.modeling.polynomial.Hermite1D", "astropy.modeling.polynomial.Hermite2D", )
[docs] def to_yaml_tree_transform(self, model, tag, ctx): poly_type = _CLASS_NAME_TO_POLY_INFO[model.__class__.__name__][0] if model.n_inputs == 1: coefficients = np.array(model.parameters) else: coefficients = np.zeros((model.x_degree + 1, model.y_degree + 1)) for i in range(model.x_degree + 1): for j in range(model.y_degree + 1): name = f"c{i}_{j}" coefficients[i, j] = getattr(model, name).value node = {"polynomial_type": poly_type, "coefficients": coefficients} if model.n_inputs == 1: if model.domain is not None: node["domain"] = model.domain if model.window is not None: node["window"] = model.window else: if model.x_domain or model.y_domain is not None: node["domain"] = (model.x_domain, model.y_domain) if model.x_window or model.y_window is not None: node["window"] = (model.x_window, model.y_window) return node
[docs] def from_yaml_tree_transform(self, node, tag, ctx): from astropy.modeling import polynomial coefficients = np.asarray(node["coefficients"]) poly_type = node["polynomial_type"] n_dim = coefficients.ndim class_name = _POLY_INFO_TO_CLASS_NAME[(poly_type, n_dim)] model_type = getattr(polynomial, class_name) coefficients = np.asarray(node["coefficients"]) if n_dim == 1: domain = node.get("domain", None) window = node.get("window", None) model = model_type(coefficients.size - 1, domain=domain, window=window) model.parameters = coefficients elif n_dim == 2: # noqa: PLR2004 x_domain, y_domain = tuple(node.get("domain", (None, None))) x_window, y_window = tuple(node.get("window", (None, None))) coeffs = {} shape = coefficients.shape x_degree = shape[0] - 1 y_degree = shape[1] - 1 for i in range(x_degree + 1): for j in range(y_degree + 1): name = f"c{i}_{j}" coeffs[name] = coefficients[i, j] model = model_type( x_degree, y_degree, x_domain=x_domain, y_domain=y_domain, x_window=x_window, y_window=y_window, **coeffs, ) else: msg = "astropy supports only 1D or 2D polynomial models" raise NotImplementedError(msg) return model