"""
.. codeauthor:: David Zwicker <david.zwicker@ds.mpg.de>
"""
from __future__ import annotations
from typing import TYPE_CHECKING
import numpy as np
from .base import CoordinatesBase
if TYPE_CHECKING:
from numpy.typing import ArrayLike
from ...tools.typing import FloatingArray
[docs]
class CartesianCoordinates(CoordinatesBase):
"""N-dimensional Cartesian coordinates."""
_objs: dict[int, CartesianCoordinates] = {}
def __new__(cls, dim: int):
# cache the instances for each dimension
if dim not in cls._objs:
cls._objs[dim] = super().__new__(cls)
return cls._objs[dim]
def __getnewargs__(self):
return (self.dim,)
def __init__(self, dim: int):
"""
Args:
dim (int):
Dimension of the Cartesian coordinate system
"""
if dim <= 0:
msg = "`dim` must be positive integer"
raise ValueError(msg)
self.dim = dim
if self.dim <= 3:
self.axes = list("xyz"[: self.dim])
else:
self.axes = [chr(97 + i) for i in range(self.dim)]
self.coordinate_limits = [(-np.inf, np.inf)] * self.dim
def __repr__(self) -> str:
"""Return instance as string."""
return f"{self.__class__.__name__}(dim={self.dim})"
def __eq__(self, other):
return self.__class__ is other.__class__ and self.dim == other.dim
def _pos_to_cart(self, points: FloatingArray) -> FloatingArray:
return points
def _pos_from_cart(self, points: FloatingArray) -> FloatingArray:
return points
def _mapping_jacobian(self, points: FloatingArray) -> FloatingArray:
jac = np.zeros((self.dim, self.dim, *points.shape[:-1]))
jac[range(self.dim), range(self.dim)] = 1
return jac
def _volume_factor(self, points: FloatingArray) -> ArrayLike:
return np.ones(points.shape[:-1])
def _cell_volume(self, c_low: FloatingArray, c_high: FloatingArray):
return np.prod(c_high - c_low, axis=-1)
def _scale_factors(self, points: FloatingArray) -> FloatingArray:
return np.ones_like(points)
def _basis_rotation(self, points: FloatingArray) -> FloatingArray:
return np.eye(self.dim)