move to simpler docstring format and improve type annotations
This commit is contained in:
parent
4e0a5ede21
commit
db9e7831b9
@ -3,8 +3,6 @@ from typing import Any
|
||||
|
||||
def is_scalar(var: Any) -> bool:
|
||||
"""
|
||||
Alias for 'not hasattr(var, "__len__")'
|
||||
|
||||
:param var: Checks if var has a length.
|
||||
Alias for `not hasattr(var, "__len__")`
|
||||
"""
|
||||
return not hasattr(var, "__len__")
|
||||
|
141
gridlock/draw.py
141
gridlock/draw.py
@ -1,9 +1,9 @@
|
||||
"""
|
||||
Drawing-related methods for Grid class
|
||||
"""
|
||||
from typing import List
|
||||
from typing import List, Optional, Union, Sequence, Callable
|
||||
|
||||
import numpy
|
||||
import numpy # type: ignore
|
||||
from numpy import diff, floor, ceil, zeros, hstack, newaxis
|
||||
|
||||
from float_raster import raster
|
||||
@ -12,27 +12,34 @@ from . import GridError, Direction
|
||||
from ._helpers import is_scalar
|
||||
|
||||
|
||||
eps_callable_t = Callable[[numpy.ndarray, numpy.ndarray, numpy.ndarray], numpy.ndarray]
|
||||
|
||||
|
||||
def draw_polygons(self,
|
||||
surface_normal: Direction or int,
|
||||
center: List or numpy.ndarray,
|
||||
polygons: List[numpy.ndarray or List],
|
||||
surface_normal: Union[Direction, int],
|
||||
center: numpy.ndarray,
|
||||
polygons: Sequence[numpy.ndarray],
|
||||
thickness: float,
|
||||
eps: List[float or eps_callable_type] or float or eps_callable_type):
|
||||
eps: Union[Sequence[Union[float, eps_callable_t]], float, eps_callable_t],
|
||||
) -> None:
|
||||
"""
|
||||
Draw polygons on an axis-aligned plane.
|
||||
|
||||
:param surface_normal: Axis normal to the plane we're drawing on. Can be a Direction or
|
||||
integer in range(3)
|
||||
:param center: 3-element ndarray or list specifying an offset applied to all the polygons
|
||||
:param polygons: List of Nx2 or Nx3 ndarrays, each specifying the vertices of a polygon
|
||||
(non-closed, clockwise). If Nx3, the surface_normal coordinate is ignored. Each polygon
|
||||
must have at least 3 vertices.
|
||||
:param thickness: Thickness of the layer to draw
|
||||
:param eps: Value to draw with ('epsilon'). Can be scalar, callable, or a list
|
||||
of any of these (1 per grid). Callable values should take ndarrays x, y, z of equal
|
||||
shape and return an ndarray of equal shape containing the eps value at the given x, y,
|
||||
and z (natural, not grid coordinates).
|
||||
:raises: GridError
|
||||
Args:
|
||||
surface_normal: Axis normal to the plane we're drawing on. Can be a `Direction` or
|
||||
integer in `range(3)`
|
||||
center: 3-element ndarray or list specifying an offset applied to all the polygons
|
||||
polygons: List of Nx2 or Nx3 ndarrays, each specifying the vertices of a polygon
|
||||
(non-closed, clockwise). If Nx3, the surface_normal coordinate is ignored. Each
|
||||
polygon must have at least 3 vertices.
|
||||
thickness: Thickness of the layer to draw
|
||||
eps: Value to draw with ('epsilon'). Can be scalar, callable, or a list
|
||||
of any of these (1 per grid). Callable values should take an ndarray the shape of the
|
||||
grid and return an ndarray of equal shape containing the eps value at the given x, y,
|
||||
and z (natural, not grid coordinates).
|
||||
|
||||
Raises:
|
||||
GridError
|
||||
"""
|
||||
# Turn surface_normal into its integer representation
|
||||
if isinstance(surface_normal, Direction):
|
||||
@ -180,39 +187,43 @@ def draw_polygons(self,
|
||||
|
||||
|
||||
def draw_polygon(self,
|
||||
surface_normal: Direction or int,
|
||||
center: List or numpy.ndarray,
|
||||
polygon: List or numpy.ndarray,
|
||||
surface_normal: Union[Direction, int],
|
||||
center: numpy.ndarray,
|
||||
polygon: numpy.ndarray,
|
||||
thickness: float,
|
||||
eps: List[float or eps_callable_type] or float or eps_callable_type):
|
||||
eps: Union[Sequence[Union[float, eps_callable_t]], float, eps_callable_t],
|
||||
) -> None:
|
||||
"""
|
||||
Draw a polygon on an axis-aligned plane.
|
||||
|
||||
:param surface_normal: Axis normal to the plane we're drawing on. Can be a Direction or
|
||||
integer in range(3)
|
||||
:param center: 3-element ndarray or list specifying an offset applied to the polygon
|
||||
:param polygon: Nx2 or Nx3 ndarray specifying the vertices of a polygon (non-closed,
|
||||
clockwise). If Nx3, the surface_normal coordinate is ignored. Must have at least 3
|
||||
vertices.
|
||||
:param thickness: Thickness of the layer to draw
|
||||
:param eps: Value to draw with ('epsilon'). See draw_polygons() for details.
|
||||
Args:
|
||||
surface_normal: Axis normal to the plane we're drawing on. Can be a Direction or
|
||||
integer in range(3)
|
||||
center: 3-element ndarray or list specifying an offset applied to the polygon
|
||||
polygon: Nx2 or Nx3 ndarray specifying the vertices of a polygon (non-closed,
|
||||
clockwise). If Nx3, the surface_normal coordinate is ignored. Must have at
|
||||
least 3 vertices.
|
||||
thickness: Thickness of the layer to draw
|
||||
eps: Value to draw with ('epsilon'). See `draw_polygons()` for details.
|
||||
"""
|
||||
self.draw_polygons(surface_normal, center, [polygon], thickness, eps)
|
||||
|
||||
|
||||
def draw_slab(self,
|
||||
surface_normal: Direction or int,
|
||||
center: List or numpy.ndarray,
|
||||
surface_normal: Union[Direction, int],
|
||||
center: numpy.ndarray,
|
||||
thickness: float,
|
||||
eps: List[float or eps_callable_type] or float or eps_callable_type):
|
||||
eps: Union[List[Union[float, eps_callable_t]], float, eps_callable_t],
|
||||
) -> None:
|
||||
"""
|
||||
Draw an axis-aligned infinite slab.
|
||||
|
||||
:param surface_normal: Axis normal to the plane we're drawing on. Can be a Direction or
|
||||
integer in range(3)
|
||||
:param center: Surface_normal coordinate at the center of the slab
|
||||
:param thickness: Thickness of the layer to draw
|
||||
:param eps: Value to draw with ('epsilon'). See draw_polygons() for details.
|
||||
Args:
|
||||
surface_normal: Axis normal to the plane we're drawing on. Can be a `Direction` or
|
||||
integer in `range(3)`
|
||||
center: Surface_normal coordinate at the center of the slab
|
||||
thickness: Thickness of the layer to draw
|
||||
eps: Value to draw with ('epsilon'). See `draw_polygons()` for details.
|
||||
"""
|
||||
# Turn surface_normal into its integer representation
|
||||
if isinstance(surface_normal, Direction):
|
||||
@ -250,16 +261,18 @@ def draw_slab(self,
|
||||
|
||||
|
||||
def draw_cuboid(self,
|
||||
center: List or numpy.ndarray,
|
||||
dimensions: List or numpy.ndarray,
|
||||
eps: List[float or eps_callable_type] or float or eps_callable_type):
|
||||
center: numpy.ndarray,
|
||||
dimensions: numpy.ndarray,
|
||||
eps: Union[List[Union[float, eps_callable_t]], float, eps_callable_t],
|
||||
) -> None:
|
||||
"""
|
||||
Draw an axis-aligned cuboid
|
||||
|
||||
:param center: 3-element ndarray or list specifying the cuboid's center
|
||||
:param dimensions: 3-element list or ndarray containing the x, y, and z edge-to-edge
|
||||
sizes of the cuboid
|
||||
:param eps: Value to draw with ('epsilon'). See draw_polygons() for details.
|
||||
Args:
|
||||
center: 3-element ndarray or list specifying the cuboid's center
|
||||
dimensions: 3-element list or ndarray containing the x, y, and z edge-to-edge
|
||||
sizes of the cuboid
|
||||
eps: Value to draw with ('epsilon'). See `draw_polygons()` for details.
|
||||
"""
|
||||
p = numpy.array([[-dimensions[0], +dimensions[1]],
|
||||
[+dimensions[0], +dimensions[1]],
|
||||
@ -270,22 +283,24 @@ def draw_cuboid(self,
|
||||
|
||||
|
||||
def draw_cylinder(self,
|
||||
surface_normal: Direction or int,
|
||||
center: List or numpy.ndarray,
|
||||
surface_normal: Union[Direction, int],
|
||||
center: numpy.ndarray,
|
||||
radius: float,
|
||||
thickness: float,
|
||||
num_points: int,
|
||||
eps: List[float or eps_callable_type] or float or eps_callable_type):
|
||||
eps: Union[List[Union[float, eps_callable_t]], float, eps_callable_t],
|
||||
) -> None:
|
||||
"""
|
||||
Draw an axis-aligned cylinder. Approximated by a num_points-gon
|
||||
|
||||
:param surface_normal: Axis normal to the plane we're drawing on. Can be a Direction or
|
||||
integer in range(3)
|
||||
:param center: 3-element ndarray or list specifying the cylinder's center
|
||||
:param radius: cylinder radius
|
||||
:param thickness: Thickness of the layer to draw
|
||||
:param num_points: The circle is approximated by a polygon with num_points vertices
|
||||
:param eps: Value to draw with ('epsilon'). See draw_polygons() for details.
|
||||
Args:
|
||||
surface_normal: Axis normal to the plane we're drawing on. Can be a `Direction` or
|
||||
integer in `range(3)`
|
||||
center: 3-element ndarray or list specifying the cylinder's center
|
||||
radius: cylinder radius
|
||||
thickness: Thickness of the layer to draw
|
||||
num_points: The circle is approximated by a polygon with `num_points` vertices
|
||||
eps: Value to draw with ('epsilon'). See `draw_polygons()` for details.
|
||||
"""
|
||||
theta = numpy.linspace(0, 2*numpy.pi, num_points, endpoint=False)
|
||||
x = radius * numpy.sin(theta)
|
||||
@ -295,17 +310,19 @@ def draw_cylinder(self,
|
||||
|
||||
|
||||
def draw_extrude_rectangle(self,
|
||||
rectangle: List or numpy.ndarray,
|
||||
direction: Direction or int,
|
||||
rectangle: numpy.ndarray,
|
||||
direction: Union[Direction, int],
|
||||
polarity: int,
|
||||
distance: float):
|
||||
distance: float,
|
||||
) -> None:
|
||||
"""
|
||||
Extrude a rectangle of a previously-drawn structure along an axis.
|
||||
|
||||
:param rectangle: 2x3 ndarray or list specifying the rectangle's corners
|
||||
:param direction: Direction to extrude in. Direction enum or int in range(3)
|
||||
:param polarity: +1 or -1, direction along axis to extrude in
|
||||
:param distance: How far to extrude
|
||||
Args:
|
||||
rectangle: 2x3 ndarray or list specifying the rectangle's corners
|
||||
direction: Direction to extrude in. Direction enum or int in range(3)
|
||||
polarity: +1 or -1, direction along axis to extrude in
|
||||
distance: How far to extrude
|
||||
"""
|
||||
# Turn extrude_direction into its integer representation
|
||||
if isinstance(direction, Direction):
|
||||
|
131
gridlock/grid.py
131
gridlock/grid.py
@ -1,6 +1,6 @@
|
||||
from typing import List, Tuple, Callable, Dict
|
||||
from typing import List, Tuple, Callable, Dict, Optional, Union, Sequence, ClassVar
|
||||
|
||||
import numpy
|
||||
import numpy # type: ignore
|
||||
from numpy import diff, floor, ceil, zeros, hstack, newaxis
|
||||
|
||||
import pickle
|
||||
@ -23,24 +23,26 @@ class Grid(object):
|
||||
is generated based on the coordinates of the boundary points). Also does
|
||||
straightforward natural <-> grid unit conversion.
|
||||
|
||||
self.grids[i][a,b,c] contains the value of epsilon for the cell located around
|
||||
`self.grids[i][a,b,c]` contains the value of epsilon for the cell located around
|
||||
```
|
||||
(xyz[0][a] + dxyz[0][a] * shifts[i, 0],
|
||||
xyz[1][b] + dxyz[1][b] * shifts[i, 1],
|
||||
xyz[2][c] + dxyz[2][c] * shifts[i, 2]).
|
||||
You can get raw edge coordinates (exyz),
|
||||
center coordinates (xyz),
|
||||
cell sizes (dxyz),
|
||||
```
|
||||
You can get raw edge coordinates (`exyz`),
|
||||
center coordinates (`xyz`),
|
||||
cell sizes (`dxyz`),
|
||||
from the properties named as above, or get them for a given grid by using the
|
||||
self.shifted_*xyz(which_shifts) functions.
|
||||
`self.shifted_*xyz(which_shifts)` functions.
|
||||
|
||||
The sizes of adjacent cells are taken into account when applying shifts. The
|
||||
total shift for each edge is chosen using (shift * dx_of_cell_being_moved_through).
|
||||
total shift for each edge is chosen using `(shift * dx_of_cell_being_moved_through)`.
|
||||
|
||||
It is tricky to determine the size of the right-most cell after shifting,
|
||||
since its right boundary should shift by shifts[i][a] * dxyz[a][dxyz[a].size],
|
||||
since its right boundary should shift by `shifts[i][a] * dxyz[a][dxyz[a].size]`,
|
||||
where the dxyz element refers to a cell that does not exist.
|
||||
Because of this, we either assume this 'ghost' cell is the same size as the last
|
||||
real cell, or, if self.periodic[a] is set to True, the same size as the first cell.
|
||||
real cell, or, if `self.periodic[a]` is set to `True`, the same size as the first cell.
|
||||
"""
|
||||
|
||||
Yee_Shifts_E = 0.5 * numpy.array([[1, 0, 0],
|
||||
@ -63,7 +65,8 @@ class Grid(object):
|
||||
"""
|
||||
Cell sizes for each axis, no shifts applied
|
||||
|
||||
:return: List of 3 ndarrays of cell sizes
|
||||
Returns:
|
||||
List of 3 ndarrays of cell sizes
|
||||
"""
|
||||
return [diff(self.exyz[a]) for a in range(3)]
|
||||
|
||||
@ -72,7 +75,8 @@ class Grid(object):
|
||||
"""
|
||||
Cell centers for each axis, no shifts applied
|
||||
|
||||
:return: List of 3 ndarrays of cell edges
|
||||
Returns:
|
||||
List of 3 ndarrays of cell edges
|
||||
"""
|
||||
return [self.exyz[a][:-1] + self.dxyz[a] / 2.0 for a in range(3)]
|
||||
|
||||
@ -81,7 +85,8 @@ class Grid(object):
|
||||
"""
|
||||
The number of cells in x, y, and z
|
||||
|
||||
:return: ndarray [x_centers.size, y_centers.size, z_centers.size]
|
||||
Returns:
|
||||
ndarray of [x_centers.size, y_centers.size, z_centers.size]
|
||||
"""
|
||||
return numpy.array([coord.size - 1 for coord in self.exyz], dtype=int)
|
||||
|
||||
@ -95,7 +100,8 @@ class Grid(object):
|
||||
If periodic, final edge shifts same amount as first
|
||||
Otherwise, final edge shifts same amount as second-to-last
|
||||
|
||||
:return: list of [dxs, dys, dzs] with each element same length as elements of self.xyz
|
||||
Returns:
|
||||
list of [dxs, dys, dzs] with each element same length as elements of `self.xyz`
|
||||
"""
|
||||
el = [0 if p else -1 for p in self.periodic]
|
||||
return [hstack((self.dxyz[a], self.dxyz[a][e])) for a, e in zip(range(3), el)]
|
||||
@ -104,7 +110,9 @@ class Grid(object):
|
||||
def center(self) -> numpy.ndarray:
|
||||
"""
|
||||
Center position of the entire grid, no shifts applied
|
||||
:return: ndarray [x_center, y_center, z_center]
|
||||
|
||||
Returns:
|
||||
ndarray of [x_center, y_center, z_center]
|
||||
"""
|
||||
# center is just average of first and last xyz, which is just the average of the
|
||||
# first two and last two exyz
|
||||
@ -118,18 +126,22 @@ class Grid(object):
|
||||
ndarrays. No shifts are applied, so these are extreme bounds on these values (as a
|
||||
weighted average is performed when shifting).
|
||||
|
||||
:return: List of 2 ndarrays, d_min=[min(dx), min(dy), min(dz)] and d_max=[...]
|
||||
Returns:
|
||||
Tuple of 2 ndarrays, `d_min=[min(dx), min(dy), min(dz)]` and `d_max=[...]`
|
||||
"""
|
||||
d_min = numpy.array([min(self.dxyz[a]) for a in range(3)], dtype=float)
|
||||
d_max = numpy.array([max(self.dxyz[a]) for a in range(3)], dtype=float)
|
||||
return d_min, d_max
|
||||
|
||||
def shifted_exyz(self, which_shifts: int or None) -> List[numpy.ndarray]:
|
||||
def shifted_exyz(self, which_shifts: Optional[int]) -> List[numpy.ndarray]:
|
||||
"""
|
||||
Returns edges for which_shifts.
|
||||
|
||||
:param which_shifts: Which grid (which shifts) to use, or None for unshifted
|
||||
:return: List of 3 ndarrays of cell edges
|
||||
Args:
|
||||
which_shifts: Which grid (which shifts) to use, or `None` for unshifted
|
||||
|
||||
Returns:
|
||||
List of 3 ndarrays of cell edges
|
||||
"""
|
||||
if which_shifts is None:
|
||||
return self.exyz
|
||||
@ -143,12 +155,15 @@ class Grid(object):
|
||||
|
||||
return [self.exyz[a] + dxyz[a] * shifts[a] for a in range(3)]
|
||||
|
||||
def shifted_dxyz(self, which_shifts: int or None) -> List[numpy.ndarray]:
|
||||
def shifted_dxyz(self, which_shifts: Optional[int]) -> List[numpy.ndarray]:
|
||||
"""
|
||||
Returns cell sizes for which_shifts.
|
||||
Returns cell sizes for `which_shifts`.
|
||||
|
||||
:param which_shifts: Which grid (which shifts) to use, or None for unshifted
|
||||
:return: List of 3 ndarrays of cell sizes
|
||||
Args:
|
||||
which_shifts: Which grid (which shifts) to use, or `None` for unshifted
|
||||
|
||||
Returns:
|
||||
List of 3 ndarrays of cell sizes
|
||||
"""
|
||||
if which_shifts is None:
|
||||
return self.dxyz
|
||||
@ -167,12 +182,15 @@ class Grid(object):
|
||||
|
||||
return sdxyz
|
||||
|
||||
def shifted_xyz(self, which_shifts: int or None) -> List[numpy.ndarray]:
|
||||
def shifted_xyz(self, which_shifts: Optional[int]) -> List[numpy.ndarray]:
|
||||
"""
|
||||
Returns cell centers for which_shifts.
|
||||
Returns cell centers for `which_shifts`.
|
||||
|
||||
:param which_shifts: Which grid (which shifts) to use, or None for unshifted
|
||||
:return: List of 3 ndarrays of cell centers
|
||||
Args:
|
||||
which_shifts: Which grid (which shifts) to use, or `None` for unshifted
|
||||
|
||||
Returns:
|
||||
List of 3 ndarrays of cell centers
|
||||
"""
|
||||
if which_shifts is None:
|
||||
return self.xyz
|
||||
@ -184,7 +202,8 @@ class Grid(object):
|
||||
"""
|
||||
Return cell widths, with each dimension shifted by the corresponding shifts.
|
||||
|
||||
:return: [grid.shifted_dxyz(which_shifts=a)[a] for a in range(3)]
|
||||
Returns:
|
||||
`[grid.shifted_dxyz(which_shifts=a)[a] for a in range(3)]`
|
||||
"""
|
||||
if len(self.grids) != 3:
|
||||
raise GridError('autoshifting requires exactly 3 grids')
|
||||
@ -192,29 +211,31 @@ class Grid(object):
|
||||
|
||||
|
||||
def __init__(self,
|
||||
pixel_edge_coordinates: List[List or numpy.ndarray],
|
||||
shifts: numpy.ndarray or List = Yee_Shifts_E,
|
||||
initial: float or numpy.ndarray or List[float] or List[numpy.ndarray] = 1.0,
|
||||
num_grids: int = None,
|
||||
periodic: bool or List[bool] = False):
|
||||
pixel_edge_coordinates: Sequence[numpy.ndarray],
|
||||
shifts: numpy.ndarray = Yee_Shifts_E,
|
||||
initial: Union[float, numpy.ndarray] = 1.0,
|
||||
num_grids: Optional[int] = None,
|
||||
periodic: Union[bool, Sequence[bool]] = False,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize a new Grid
|
||||
Args:
|
||||
pixel_edge_coordinates: 3-element list of (ndarrays or lists) specifying the
|
||||
coordinates of the pixel edges in each dimensions
|
||||
(ie, `[[x0, x1, x2,...], [y0,...], [z0,...]]` where the first pixel has x-edges x=`x0` and
|
||||
x=`x1`, the second has edges x=`x1` and x=`x2`, etc.)
|
||||
shifts: Nx3 array containing `[x, y, z]` offsets for each of N grids.
|
||||
E-field Yee shifts are used by default.
|
||||
initial: Grids are initialized to this value. If scalar, all grids are initialized
|
||||
with ndarrays full of the scalar. If a list of scalars, `grid[i]` is initialized to an
|
||||
ndarray full of `initial[i]`. If a list of ndarrays of the same shape as the grids, `grid[i]`
|
||||
is set to `initial[i]`. Default `1.0`.
|
||||
num_grids: How many grids to create. Must be <= `shifts.shape[0]`.
|
||||
Default is `shifts.shape[0]`
|
||||
periodic: Specifies how the sizes of edge cells are calculated; see main class
|
||||
documentation. List of 3 bool, or a single bool that gets broadcast. Default `False`.
|
||||
|
||||
:param pixel_edge_coordinates: 3-element list of (ndarrays or lists) specifying the
|
||||
coordinates of the pixel edges in each dimensions
|
||||
(ie, [[x0, x1, x2,...], [y0,...], [z0,...]] where the first pixel has x-edges x=x0 and
|
||||
x=x1, the second has edges x=x1 and x=x2, etc.)
|
||||
:param shifts: Nx3 array containing [x, y, z] offsets for each of N grids.
|
||||
E-field Yee shifts are used by default.
|
||||
:param initial: Grids are initialized to this value. If scalar, all grids are initialized
|
||||
with ndarrays full of the scalar. If a list of scalars, grid[i] is initialized to an
|
||||
ndarray full of initial[i]. If a list of ndarrays of the same shape as the grids, grid[i]
|
||||
is set to initial[i]. Default 1.
|
||||
:param num_grids: How many grids to create. Must be <= shifts.shape[0].
|
||||
Default is shifts.shape[0]
|
||||
:param periodic: Specifies how the sizes of edge cells are calculated; see main class
|
||||
documentation. List of 3 bool, or a single bool that gets broadcast. Default False.
|
||||
:raises: GridError
|
||||
Raises:
|
||||
`GridError` on invalid input
|
||||
"""
|
||||
self.exyz = [numpy.unique(pixel_edge_coordinates[i]) for i in range(3)] # type: List[numpy.ndarray]
|
||||
"""Cell edges. Monotonically increasing without duplicates."""
|
||||
@ -280,7 +301,8 @@ class Grid(object):
|
||||
"""
|
||||
Load a grid from a file
|
||||
|
||||
:param filename: Filename to load from.
|
||||
Args:
|
||||
filename: Filename to load from.
|
||||
"""
|
||||
with open(filename, 'rb') as f:
|
||||
tmp_dict = pickle.load(f)
|
||||
@ -293,16 +315,15 @@ class Grid(object):
|
||||
"""
|
||||
Save to file.
|
||||
|
||||
:param filename: Filename to save to.
|
||||
Args:
|
||||
filename: Filename to save to.
|
||||
"""
|
||||
with open(filename, 'wb') as f:
|
||||
pickle.dump(self.__dict__, f, protocol=2)
|
||||
|
||||
def copy(self):
|
||||
"""
|
||||
Return a deep copy of the grid.
|
||||
|
||||
:return: Deep copy of the grid.
|
||||
Returns:
|
||||
Deep copy of the grid.
|
||||
"""
|
||||
return copy.deepcopy(self)
|
||||
|
||||
|
@ -1,34 +1,39 @@
|
||||
"""
|
||||
Position-related methods for Grid class
|
||||
"""
|
||||
from typing import List, Optional
|
||||
|
||||
from typing import List
|
||||
|
||||
import numpy
|
||||
import numpy # type: ignore
|
||||
from numpy import zeros
|
||||
|
||||
from . import GridError
|
||||
|
||||
|
||||
def ind2pos(self,
|
||||
ind: numpy.ndarray or List,
|
||||
which_shifts: int = None,
|
||||
ind: numpy.ndarray,
|
||||
which_shifts: Optional[int] = None,
|
||||
round_ind: bool = True,
|
||||
check_bounds: bool = True
|
||||
) -> numpy.ndarray:
|
||||
"""
|
||||
Returns the natural position corresponding to the specified cell center indices.
|
||||
The resulting position is clipped to the bounds of the grid
|
||||
(to cell centers if round_ind=True, or cell outer edges if round_ind=False)
|
||||
(to cell centers if `round_ind=True`, or cell outer edges if `round_ind=False`)
|
||||
|
||||
:param ind: Indices of the position. Can be fractional. (3-element ndarray or list)
|
||||
:param which_shifts: which grid number (shifts) to use
|
||||
:param round_ind: Whether to round ind to the nearest integer position before indexing
|
||||
(default True)
|
||||
:param check_bounds: Whether to raise an GridError if the provided ind is outside of
|
||||
the grid, as defined above (centers if round_ind, else edges) (default True)
|
||||
:return: 3-element ndarray specifying the natural position
|
||||
:raises: GridError
|
||||
Args:
|
||||
ind: Indices of the position. Can be fractional. (3-element ndarray or list)
|
||||
which_shifts: which grid number (`shifts`) to use
|
||||
round_ind: Whether to round ind to the nearest integer position before indexing
|
||||
(default `True`)
|
||||
check_bounds: Whether to raise an `GridError` if the provided ind is outside of
|
||||
the grid, as defined above (centers if `round_ind`, else edges) (default `True`)
|
||||
|
||||
Returns:
|
||||
3-element ndarray specifying the natural position
|
||||
|
||||
Raises:
|
||||
`GridError` if invalid `which_shifts`
|
||||
`GridError` if `check_bounds` and out of bounds
|
||||
"""
|
||||
if which_shifts is not None and which_shifts >= self.shifts.shape[0]:
|
||||
raise GridError('Invalid shifts')
|
||||
@ -56,21 +61,27 @@ def ind2pos(self,
|
||||
|
||||
|
||||
def pos2ind(self,
|
||||
r: numpy.ndarray or List,
|
||||
which_shifts: int or None,
|
||||
round_ind: bool=True,
|
||||
check_bounds: bool=True
|
||||
r: numpy.ndarray,
|
||||
which_shifts: Optional[int],
|
||||
round_ind: bool = True,
|
||||
check_bounds: bool = True
|
||||
) -> numpy.ndarray:
|
||||
"""
|
||||
Returns the cell-center indices corresponding to the specified natural position.
|
||||
The resulting position is clipped to within the outer centers of the grid.
|
||||
|
||||
:param r: Natural position that we will convert into indices (3-element ndarray or list)
|
||||
:param which_shifts: which grid number (shifts) to use
|
||||
:param round_ind: Whether to round the returned indices to the nearest integers.
|
||||
:param check_bounds: Whether to throw an GridError if r is outside the grid edges
|
||||
:return: 3-element ndarray specifying the indices
|
||||
:raises: GridError
|
||||
Args:
|
||||
r: Natural position that we will convert into indices (3-element ndarray or list)
|
||||
which_shifts: which grid number (`shifts`) to use
|
||||
round_ind: Whether to round the returned indices to the nearest integers.
|
||||
check_bounds: Whether to throw an `GridError` if `r` is outside the grid edges
|
||||
|
||||
Returns:
|
||||
3-element ndarray specifying the indices
|
||||
|
||||
Raises:
|
||||
`GridError` if invalid `which_shifts`
|
||||
`GridError` if `check_bounds` and out of bounds
|
||||
"""
|
||||
r = numpy.squeeze(r)
|
||||
if r.size != 3:
|
||||
|
@ -1,9 +1,9 @@
|
||||
"""
|
||||
Readback and visualization methods for Grid class
|
||||
"""
|
||||
from typing import Dict
|
||||
from typing import Dict, Optional, Union, Any
|
||||
|
||||
import numpy
|
||||
import numpy # type: ignore
|
||||
from numpy import floor, ceil, zeros
|
||||
|
||||
from . import GridError, Direction
|
||||
@ -15,21 +15,24 @@ from ._helpers import is_scalar
|
||||
|
||||
|
||||
def get_slice(self,
|
||||
surface_normal: Direction or int,
|
||||
surface_normal: Union[Direction, int],
|
||||
center: float,
|
||||
which_shifts: int = 0,
|
||||
sample_period: int = 1
|
||||
) -> numpy.ndarray:
|
||||
"""
|
||||
Retrieve a slice of a grid.
|
||||
Interpolates if given a position between two planes.
|
||||
Retrieve a slice of a grid.
|
||||
Interpolates if given a position between two planes.
|
||||
|
||||
:param surface_normal: Axis normal to the plane we're displaying. Can be a Direction or
|
||||
integer in range(3)
|
||||
:param center: Scalar specifying position along surface_normal axis.
|
||||
:param which_shifts: Which grid to display. Default is the first grid (0).
|
||||
:param sample_period: Period for down-sampling the image. Default 1 (disabled)
|
||||
:return Array containing the portion of the grid.
|
||||
Args:
|
||||
surface_normal: Axis normal to the plane we're displaying. Can be a `Direction` or
|
||||
integer in `range(3)`
|
||||
center: Scalar specifying position along surface_normal axis.
|
||||
which_shifts: Which grid to display. Default is the first grid (0).
|
||||
sample_period: Period for down-sampling the image. Default 1 (disabled)
|
||||
|
||||
Returns:
|
||||
Array containing the portion of the grid.
|
||||
"""
|
||||
if not is_scalar(center) and numpy.isreal(center):
|
||||
raise GridError('center must be a real scalar')
|
||||
@ -77,22 +80,24 @@ def get_slice(self,
|
||||
|
||||
|
||||
def visualize_slice(self,
|
||||
surface_normal: Direction or int,
|
||||
surface_normal: Union[Direction, int],
|
||||
center: float,
|
||||
which_shifts: int = 0,
|
||||
sample_period: int = 1,
|
||||
finalize: bool = True,
|
||||
pcolormesh_args: Dict = None):
|
||||
pcolormesh_args: Optional[Dict[str, Any]] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Visualize a slice of a grid.
|
||||
Interpolates if given a position between two planes.
|
||||
|
||||
:param surface_normal: Axis normal to the plane we're displaying. Can be a Direction or
|
||||
integer in range(3)
|
||||
:param center: Scalar specifying position along surface_normal axis.
|
||||
:param which_shifts: Which grid to display. Default is the first grid (0).
|
||||
:param sample_period: Period for down-sampling the image. Default 1 (disabled)
|
||||
:param finalize: Whether to call pyplot.show() after constructing the plot. Default True
|
||||
Args:
|
||||
surface_normal: Axis normal to the plane we're displaying. Can be a `Direction` or
|
||||
integer in `range(3)`
|
||||
center: Scalar specifying position along surface_normal axis.
|
||||
which_shifts: Which grid to display. Default is the first grid (0).
|
||||
sample_period: Period for down-sampling the image. Default 1 (disabled)
|
||||
finalize: Whether to call `pyplot.show()` after constructing the plot. Default `True`
|
||||
"""
|
||||
from matplotlib import pyplot
|
||||
|
||||
@ -125,19 +130,21 @@ def visualize_slice(self,
|
||||
|
||||
|
||||
def visualize_isosurface(self,
|
||||
level: float = None,
|
||||
level: Optional[float] = None,
|
||||
which_shifts: int = 0,
|
||||
sample_period: int = 1,
|
||||
show_edges: bool = True,
|
||||
finalize: bool = True):
|
||||
finalize: bool = True,
|
||||
) -> None:
|
||||
"""
|
||||
Draw an isosurface plot of the device.
|
||||
|
||||
:param level: Value at which to find isosurface. Default (None) uses mean value in grid.
|
||||
:param which_shifts: Which grid to display. Default is the first grid (0).
|
||||
:param sample_period: Period for down-sampling the image. Default 1 (disabled)
|
||||
:param show_edges: Whether to draw triangle edges. Default True
|
||||
:param finalize: Whether to call pyplot.show() after constructing the plot. Default True
|
||||
Args:
|
||||
level: Value at which to find isosurface. Default (None) uses mean value in grid.
|
||||
which_shifts: Which grid to display. Default is the first grid (0).
|
||||
sample_period: Period for down-sampling the image. Default 1 (disabled)
|
||||
show_edges: Whether to draw triangle edges. Default `True`
|
||||
finalize: Whether to call `pyplot.show()` after constructing the plot. Default `True`
|
||||
"""
|
||||
from matplotlib import pyplot
|
||||
import skimage.measure
|
||||
|
Loading…
Reference in New Issue
Block a user