Source code for cratermaker.components.surface.icosphere
import math
from pathlib import Path
from typing import Any
from numpy.typing import NDArray
from cratermaker.components.surface import Surface
from cratermaker.components.target import Target
from cratermaker.utils.general_utils import format_large_units, parameter
[docs]
@Surface.register("icosphere")
class IcosphereSurface(Surface):
"""
Create a uniform grid configuration using an icosphere. This is the most accurate and efficient way to create a uniform grid, but is limited to a few resolutions.
Parameters
----------
gridlevel : float, default 8
The subdivision level of the icosphere.
target : Target, optional
The target body or name of a known target body for the impact simulation.
reset : bool, optional
Flag to indicate whether to reset the surface. Default is True.
regrid : bool, optional
Flag to indicate whether to regrid the surface. Default is False.
simdir : str | Path
|simdir|
Returns
-------
IcosphereSurface
An instance of the IcosphereSurface class initialized with the given pixel size.
Notes
-----
The number of faces of the icosphere is given by the formula:
.. math::
n_{face} = 10 * 4^{gridlevel} + 2
The number of nodes is given by the formula:
.. math::
n_{node} = 20 * 4^{gridlevel}
"""
def __init__(
self,
gridlevel: int = 8,
target: Target | str | None = None,
reset: bool = True,
regrid: bool = False,
simdir: str | Path | None = None,
**kwargs: Any,
):
super().__init__(target=target, simdir=simdir, **kwargs)
self.gridlevel = gridlevel
self._load_from_files(reset=reset, regrid=regrid, **kwargs)
def __str__(self) -> str:
str_repr = super().__str__()
pix_mean = format_large_units(self.pix_mean, quantity="length")
pix_std = format_large_units(self.pix_std, quantity="length")
str_repr += f"Grid Level: {self.gridlevel}\n"
str_repr += f"Effective pixel size: {pix_mean} +/- {pix_std}\n"
return str_repr
@property
def _hashvars(self):
"""
The variables used to generate the hash.
"""
return super()._hashvars + [self.gridlevel]
def _generate_face_distribution(self, **kwargs: Any) -> NDArray:
"""
Creates the points that define the mesh centers.
Returns
-------
(3,n) ndarray of np.float64
Array of points on a unit sphere.
"""
from trimesh.creation import icosphere
print(f"Generating a mesh with icosphere level {self.gridlevel}.")
mesh = icosphere(self.gridlevel)
points = mesh.vertices.T
return points
@parameter
def gridlevel(self) -> int:
"""The subdivision level of the icosphere."""
return self._gridlevel
@gridlevel.setter
def gridlevel(self, value: int) -> None:
if value < 0:
raise ValueError("The value of gridlevel must be a non-negative integer.")
self._gridlevel = int(value)
@property
def pix(self) -> float:
"""The approximate face size for a cell of the mesh in meters."""
if self._pix is None:
nfaces = 10 * 4**self.gridlevel + 2
self._pix = (4 * math.pi * self.radius**2 / nfaces) ** 0.5
return self._pix