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:
|
def is_scalar(var: Any) -> bool:
|
||||||
"""
|
"""
|
||||||
Alias for 'not hasattr(var, "__len__")'
|
Alias for `not hasattr(var, "__len__")`
|
||||||
|
|
||||||
:param var: Checks if var has a length.
|
|
||||||
"""
|
"""
|
||||||
return 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
|
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 numpy import diff, floor, ceil, zeros, hstack, newaxis
|
||||||
|
|
||||||
from float_raster import raster
|
from float_raster import raster
|
||||||
@ -12,27 +12,34 @@ from . import GridError, Direction
|
|||||||
from ._helpers import is_scalar
|
from ._helpers import is_scalar
|
||||||
|
|
||||||
|
|
||||||
|
eps_callable_t = Callable[[numpy.ndarray, numpy.ndarray, numpy.ndarray], numpy.ndarray]
|
||||||
|
|
||||||
|
|
||||||
def draw_polygons(self,
|
def draw_polygons(self,
|
||||||
surface_normal: Direction or int,
|
surface_normal: Union[Direction, int],
|
||||||
center: List or numpy.ndarray,
|
center: numpy.ndarray,
|
||||||
polygons: List[numpy.ndarray or List],
|
polygons: Sequence[numpy.ndarray],
|
||||||
thickness: float,
|
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.
|
Draw polygons on an axis-aligned plane.
|
||||||
|
|
||||||
:param surface_normal: Axis normal to the plane we're drawing on. Can be a Direction or
|
Args:
|
||||||
integer in range(3)
|
surface_normal: Axis normal to the plane we're drawing on. Can be a `Direction` or
|
||||||
:param center: 3-element ndarray or list specifying an offset applied to all the polygons
|
integer in `range(3)`
|
||||||
:param polygons: List of Nx2 or Nx3 ndarrays, each specifying the vertices of a polygon
|
center: 3-element ndarray or list specifying an offset applied to all the polygons
|
||||||
(non-closed, clockwise). If Nx3, the surface_normal coordinate is ignored. Each polygon
|
polygons: List of Nx2 or Nx3 ndarrays, each specifying the vertices of a polygon
|
||||||
must have at least 3 vertices.
|
(non-closed, clockwise). If Nx3, the surface_normal coordinate is ignored. Each
|
||||||
:param thickness: Thickness of the layer to draw
|
polygon must have at least 3 vertices.
|
||||||
:param eps: Value to draw with ('epsilon'). Can be scalar, callable, or a list
|
thickness: Thickness of the layer to draw
|
||||||
of any of these (1 per grid). Callable values should take ndarrays x, y, z of equal
|
eps: Value to draw with ('epsilon'). Can be scalar, callable, or a list
|
||||||
shape and return an ndarray of equal shape containing the eps value at the given x, y,
|
of any of these (1 per grid). Callable values should take an ndarray the shape of the
|
||||||
and z (natural, not grid coordinates).
|
grid and return an ndarray of equal shape containing the eps value at the given x, y,
|
||||||
:raises: GridError
|
and z (natural, not grid coordinates).
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
GridError
|
||||||
"""
|
"""
|
||||||
# Turn surface_normal into its integer representation
|
# Turn surface_normal into its integer representation
|
||||||
if isinstance(surface_normal, Direction):
|
if isinstance(surface_normal, Direction):
|
||||||
@ -180,39 +187,43 @@ def draw_polygons(self,
|
|||||||
|
|
||||||
|
|
||||||
def draw_polygon(self,
|
def draw_polygon(self,
|
||||||
surface_normal: Direction or int,
|
surface_normal: Union[Direction, int],
|
||||||
center: List or numpy.ndarray,
|
center: numpy.ndarray,
|
||||||
polygon: List or numpy.ndarray,
|
polygon: numpy.ndarray,
|
||||||
thickness: float,
|
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.
|
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
|
Args:
|
||||||
integer in range(3)
|
surface_normal: Axis normal to the plane we're drawing on. Can be a Direction or
|
||||||
:param center: 3-element ndarray or list specifying an offset applied to the polygon
|
integer in range(3)
|
||||||
:param polygon: Nx2 or Nx3 ndarray specifying the vertices of a polygon (non-closed,
|
center: 3-element ndarray or list specifying an offset applied to the polygon
|
||||||
clockwise). If Nx3, the surface_normal coordinate is ignored. Must have at least 3
|
polygon: Nx2 or Nx3 ndarray specifying the vertices of a polygon (non-closed,
|
||||||
vertices.
|
clockwise). If Nx3, the surface_normal coordinate is ignored. Must have at
|
||||||
:param thickness: Thickness of the layer to draw
|
least 3 vertices.
|
||||||
:param eps: Value to draw with ('epsilon'). See draw_polygons() for details.
|
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)
|
self.draw_polygons(surface_normal, center, [polygon], thickness, eps)
|
||||||
|
|
||||||
|
|
||||||
def draw_slab(self,
|
def draw_slab(self,
|
||||||
surface_normal: Direction or int,
|
surface_normal: Union[Direction, int],
|
||||||
center: List or numpy.ndarray,
|
center: numpy.ndarray,
|
||||||
thickness: float,
|
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.
|
Draw an axis-aligned infinite slab.
|
||||||
|
|
||||||
:param surface_normal: Axis normal to the plane we're drawing on. Can be a Direction or
|
Args:
|
||||||
integer in range(3)
|
surface_normal: Axis normal to the plane we're drawing on. Can be a `Direction` or
|
||||||
:param center: Surface_normal coordinate at the center of the slab
|
integer in `range(3)`
|
||||||
:param thickness: Thickness of the layer to draw
|
center: Surface_normal coordinate at the center of the slab
|
||||||
:param eps: Value to draw with ('epsilon'). See draw_polygons() for details.
|
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
|
# Turn surface_normal into its integer representation
|
||||||
if isinstance(surface_normal, Direction):
|
if isinstance(surface_normal, Direction):
|
||||||
@ -250,16 +261,18 @@ def draw_slab(self,
|
|||||||
|
|
||||||
|
|
||||||
def draw_cuboid(self,
|
def draw_cuboid(self,
|
||||||
center: List or numpy.ndarray,
|
center: numpy.ndarray,
|
||||||
dimensions: List or numpy.ndarray,
|
dimensions: numpy.ndarray,
|
||||||
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 cuboid
|
Draw an axis-aligned cuboid
|
||||||
|
|
||||||
:param center: 3-element ndarray or list specifying the cuboid's center
|
Args:
|
||||||
:param dimensions: 3-element list or ndarray containing the x, y, and z edge-to-edge
|
center: 3-element ndarray or list specifying the cuboid's center
|
||||||
sizes of the cuboid
|
dimensions: 3-element list or ndarray containing the x, y, and z edge-to-edge
|
||||||
:param eps: Value to draw with ('epsilon'). See draw_polygons() for details.
|
sizes of the cuboid
|
||||||
|
eps: Value to draw with ('epsilon'). See `draw_polygons()` for details.
|
||||||
"""
|
"""
|
||||||
p = numpy.array([[-dimensions[0], +dimensions[1]],
|
p = numpy.array([[-dimensions[0], +dimensions[1]],
|
||||||
[+dimensions[0], +dimensions[1]],
|
[+dimensions[0], +dimensions[1]],
|
||||||
@ -270,22 +283,24 @@ def draw_cuboid(self,
|
|||||||
|
|
||||||
|
|
||||||
def draw_cylinder(self,
|
def draw_cylinder(self,
|
||||||
surface_normal: Direction or int,
|
surface_normal: Union[Direction, int],
|
||||||
center: List or numpy.ndarray,
|
center: numpy.ndarray,
|
||||||
radius: float,
|
radius: float,
|
||||||
thickness: float,
|
thickness: float,
|
||||||
num_points: int,
|
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
|
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
|
Args:
|
||||||
integer in range(3)
|
surface_normal: Axis normal to the plane we're drawing on. Can be a `Direction` or
|
||||||
:param center: 3-element ndarray or list specifying the cylinder's center
|
integer in `range(3)`
|
||||||
:param radius: cylinder radius
|
center: 3-element ndarray or list specifying the cylinder's center
|
||||||
:param thickness: Thickness of the layer to draw
|
radius: cylinder radius
|
||||||
:param num_points: The circle is approximated by a polygon with num_points vertices
|
thickness: Thickness of the layer to draw
|
||||||
:param eps: Value to draw with ('epsilon'). See draw_polygons() for details.
|
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)
|
theta = numpy.linspace(0, 2*numpy.pi, num_points, endpoint=False)
|
||||||
x = radius * numpy.sin(theta)
|
x = radius * numpy.sin(theta)
|
||||||
@ -295,17 +310,19 @@ def draw_cylinder(self,
|
|||||||
|
|
||||||
|
|
||||||
def draw_extrude_rectangle(self,
|
def draw_extrude_rectangle(self,
|
||||||
rectangle: List or numpy.ndarray,
|
rectangle: numpy.ndarray,
|
||||||
direction: Direction or int,
|
direction: Union[Direction, int],
|
||||||
polarity: int,
|
polarity: int,
|
||||||
distance: float):
|
distance: float,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Extrude a rectangle of a previously-drawn structure along an axis.
|
Extrude a rectangle of a previously-drawn structure along an axis.
|
||||||
|
|
||||||
:param rectangle: 2x3 ndarray or list specifying the rectangle's corners
|
Args:
|
||||||
:param direction: Direction to extrude in. Direction enum or int in range(3)
|
rectangle: 2x3 ndarray or list specifying the rectangle's corners
|
||||||
:param polarity: +1 or -1, direction along axis to extrude in
|
direction: Direction to extrude in. Direction enum or int in range(3)
|
||||||
:param distance: How far to extrude
|
polarity: +1 or -1, direction along axis to extrude in
|
||||||
|
distance: How far to extrude
|
||||||
"""
|
"""
|
||||||
# Turn extrude_direction into its integer representation
|
# Turn extrude_direction into its integer representation
|
||||||
if isinstance(direction, Direction):
|
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
|
from numpy import diff, floor, ceil, zeros, hstack, newaxis
|
||||||
|
|
||||||
import pickle
|
import pickle
|
||||||
@ -23,24 +23,26 @@ class Grid(object):
|
|||||||
is generated based on the coordinates of the boundary points). Also does
|
is generated based on the coordinates of the boundary points). Also does
|
||||||
straightforward natural <-> grid unit conversion.
|
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[0][a] + dxyz[0][a] * shifts[i, 0],
|
||||||
xyz[1][b] + dxyz[1][b] * shifts[i, 1],
|
xyz[1][b] + dxyz[1][b] * shifts[i, 1],
|
||||||
xyz[2][c] + dxyz[2][c] * shifts[i, 2]).
|
xyz[2][c] + dxyz[2][c] * shifts[i, 2]).
|
||||||
You can get raw edge coordinates (exyz),
|
```
|
||||||
center coordinates (xyz),
|
You can get raw edge coordinates (`exyz`),
|
||||||
cell sizes (dxyz),
|
center coordinates (`xyz`),
|
||||||
|
cell sizes (`dxyz`),
|
||||||
from the properties named as above, or get them for a given grid by using the
|
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
|
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,
|
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.
|
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
|
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],
|
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
|
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)]
|
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
|
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)]
|
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
|
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)
|
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
|
If periodic, final edge shifts same amount as first
|
||||||
Otherwise, final edge shifts same amount as second-to-last
|
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]
|
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)]
|
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:
|
def center(self) -> numpy.ndarray:
|
||||||
"""
|
"""
|
||||||
Center position of the entire grid, no shifts applied
|
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
|
# center is just average of first and last xyz, which is just the average of the
|
||||||
# first two and last two exyz
|
# 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
|
ndarrays. No shifts are applied, so these are extreme bounds on these values (as a
|
||||||
weighted average is performed when shifting).
|
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_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)
|
d_max = numpy.array([max(self.dxyz[a]) for a in range(3)], dtype=float)
|
||||||
return d_min, d_max
|
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.
|
Returns edges for which_shifts.
|
||||||
|
|
||||||
:param which_shifts: Which grid (which shifts) to use, or None for unshifted
|
Args:
|
||||||
:return: List of 3 ndarrays of cell edges
|
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:
|
if which_shifts is None:
|
||||||
return self.exyz
|
return self.exyz
|
||||||
@ -143,12 +155,15 @@ class Grid(object):
|
|||||||
|
|
||||||
return [self.exyz[a] + dxyz[a] * shifts[a] for a in range(3)]
|
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
|
Args:
|
||||||
:return: List of 3 ndarrays of cell sizes
|
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:
|
if which_shifts is None:
|
||||||
return self.dxyz
|
return self.dxyz
|
||||||
@ -167,12 +182,15 @@ class Grid(object):
|
|||||||
|
|
||||||
return sdxyz
|
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
|
Args:
|
||||||
:return: List of 3 ndarrays of cell centers
|
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:
|
if which_shifts is None:
|
||||||
return self.xyz
|
return self.xyz
|
||||||
@ -184,7 +202,8 @@ class Grid(object):
|
|||||||
"""
|
"""
|
||||||
Return cell widths, with each dimension shifted by the corresponding shifts.
|
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:
|
if len(self.grids) != 3:
|
||||||
raise GridError('autoshifting requires exactly 3 grids')
|
raise GridError('autoshifting requires exactly 3 grids')
|
||||||
@ -192,29 +211,31 @@ class Grid(object):
|
|||||||
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
pixel_edge_coordinates: List[List or numpy.ndarray],
|
pixel_edge_coordinates: Sequence[numpy.ndarray],
|
||||||
shifts: numpy.ndarray or List = Yee_Shifts_E,
|
shifts: numpy.ndarray = Yee_Shifts_E,
|
||||||
initial: float or numpy.ndarray or List[float] or List[numpy.ndarray] = 1.0,
|
initial: Union[float, numpy.ndarray] = 1.0,
|
||||||
num_grids: int = None,
|
num_grids: Optional[int] = None,
|
||||||
periodic: bool or List[bool] = False):
|
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
|
Raises:
|
||||||
coordinates of the pixel edges in each dimensions
|
`GridError` on invalid input
|
||||||
(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
|
|
||||||
"""
|
"""
|
||||||
self.exyz = [numpy.unique(pixel_edge_coordinates[i]) for i in range(3)] # type: List[numpy.ndarray]
|
self.exyz = [numpy.unique(pixel_edge_coordinates[i]) for i in range(3)] # type: List[numpy.ndarray]
|
||||||
"""Cell edges. Monotonically increasing without duplicates."""
|
"""Cell edges. Monotonically increasing without duplicates."""
|
||||||
@ -280,7 +301,8 @@ class Grid(object):
|
|||||||
"""
|
"""
|
||||||
Load a grid from a file
|
Load a grid from a file
|
||||||
|
|
||||||
:param filename: Filename to load from.
|
Args:
|
||||||
|
filename: Filename to load from.
|
||||||
"""
|
"""
|
||||||
with open(filename, 'rb') as f:
|
with open(filename, 'rb') as f:
|
||||||
tmp_dict = pickle.load(f)
|
tmp_dict = pickle.load(f)
|
||||||
@ -293,16 +315,15 @@ class Grid(object):
|
|||||||
"""
|
"""
|
||||||
Save to file.
|
Save to file.
|
||||||
|
|
||||||
:param filename: Filename to save to.
|
Args:
|
||||||
|
filename: Filename to save to.
|
||||||
"""
|
"""
|
||||||
with open(filename, 'wb') as f:
|
with open(filename, 'wb') as f:
|
||||||
pickle.dump(self.__dict__, f, protocol=2)
|
pickle.dump(self.__dict__, f, protocol=2)
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
"""
|
"""
|
||||||
Return a deep copy of the grid.
|
Returns:
|
||||||
|
Deep copy of the grid.
|
||||||
:return: Deep copy of the grid.
|
|
||||||
"""
|
"""
|
||||||
return copy.deepcopy(self)
|
return copy.deepcopy(self)
|
||||||
|
|
||||||
|
@ -1,34 +1,39 @@
|
|||||||
"""
|
"""
|
||||||
Position-related methods for Grid class
|
Position-related methods for Grid class
|
||||||
"""
|
"""
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
from typing import List
|
import numpy # type: ignore
|
||||||
|
|
||||||
import numpy
|
|
||||||
from numpy import zeros
|
from numpy import zeros
|
||||||
|
|
||||||
from . import GridError
|
from . import GridError
|
||||||
|
|
||||||
|
|
||||||
def ind2pos(self,
|
def ind2pos(self,
|
||||||
ind: numpy.ndarray or List,
|
ind: numpy.ndarray,
|
||||||
which_shifts: int = None,
|
which_shifts: Optional[int] = None,
|
||||||
round_ind: bool = True,
|
round_ind: bool = True,
|
||||||
check_bounds: bool = True
|
check_bounds: bool = True
|
||||||
) -> numpy.ndarray:
|
) -> numpy.ndarray:
|
||||||
"""
|
"""
|
||||||
Returns the natural position corresponding to the specified cell center indices.
|
Returns the natural position corresponding to the specified cell center indices.
|
||||||
The resulting position is clipped to the bounds of the grid
|
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)
|
Args:
|
||||||
:param which_shifts: which grid number (shifts) to use
|
ind: Indices of the position. Can be fractional. (3-element ndarray or list)
|
||||||
:param round_ind: Whether to round ind to the nearest integer position before indexing
|
which_shifts: which grid number (`shifts`) to use
|
||||||
(default True)
|
round_ind: Whether to round ind to the nearest integer position before indexing
|
||||||
:param check_bounds: Whether to raise an GridError if the provided ind is outside of
|
(default `True`)
|
||||||
the grid, as defined above (centers if round_ind, else edges) (default True)
|
check_bounds: Whether to raise an `GridError` if the provided ind is outside of
|
||||||
:return: 3-element ndarray specifying the natural position
|
the grid, as defined above (centers if `round_ind`, else edges) (default `True`)
|
||||||
:raises: GridError
|
|
||||||
|
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]:
|
if which_shifts is not None and which_shifts >= self.shifts.shape[0]:
|
||||||
raise GridError('Invalid shifts')
|
raise GridError('Invalid shifts')
|
||||||
@ -56,21 +61,27 @@ def ind2pos(self,
|
|||||||
|
|
||||||
|
|
||||||
def pos2ind(self,
|
def pos2ind(self,
|
||||||
r: numpy.ndarray or List,
|
r: numpy.ndarray,
|
||||||
which_shifts: int or None,
|
which_shifts: Optional[int],
|
||||||
round_ind: bool=True,
|
round_ind: bool = True,
|
||||||
check_bounds: bool=True
|
check_bounds: bool = True
|
||||||
) -> numpy.ndarray:
|
) -> numpy.ndarray:
|
||||||
"""
|
"""
|
||||||
Returns the cell-center indices corresponding to the specified natural position.
|
Returns the cell-center indices corresponding to the specified natural position.
|
||||||
The resulting position is clipped to within the outer centers of the grid.
|
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)
|
Args:
|
||||||
:param which_shifts: which grid number (shifts) to use
|
r: Natural position that we will convert into indices (3-element ndarray or list)
|
||||||
:param round_ind: Whether to round the returned indices to the nearest integers.
|
which_shifts: which grid number (`shifts`) to use
|
||||||
:param check_bounds: Whether to throw an GridError if r is outside the grid edges
|
round_ind: Whether to round the returned indices to the nearest integers.
|
||||||
:return: 3-element ndarray specifying the indices
|
check_bounds: Whether to throw an `GridError` if `r` is outside the grid edges
|
||||||
:raises: GridError
|
|
||||||
|
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)
|
r = numpy.squeeze(r)
|
||||||
if r.size != 3:
|
if r.size != 3:
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"""
|
"""
|
||||||
Readback and visualization methods for Grid class
|
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 numpy import floor, ceil, zeros
|
||||||
|
|
||||||
from . import GridError, Direction
|
from . import GridError, Direction
|
||||||
@ -15,21 +15,24 @@ from ._helpers import is_scalar
|
|||||||
|
|
||||||
|
|
||||||
def get_slice(self,
|
def get_slice(self,
|
||||||
surface_normal: Direction or int,
|
surface_normal: Union[Direction, int],
|
||||||
center: float,
|
center: float,
|
||||||
which_shifts: int = 0,
|
which_shifts: int = 0,
|
||||||
sample_period: int = 1
|
sample_period: int = 1
|
||||||
) -> numpy.ndarray:
|
) -> numpy.ndarray:
|
||||||
"""
|
"""
|
||||||
Retrieve a slice of a grid.
|
Retrieve a slice of a grid.
|
||||||
Interpolates if given a position between two planes.
|
Interpolates if given a position between two planes.
|
||||||
|
|
||||||
:param surface_normal: Axis normal to the plane we're displaying. Can be a Direction or
|
Args:
|
||||||
integer in range(3)
|
surface_normal: Axis normal to the plane we're displaying. Can be a `Direction` or
|
||||||
:param center: Scalar specifying position along surface_normal axis.
|
integer in `range(3)`
|
||||||
:param which_shifts: Which grid to display. Default is the first grid (0).
|
center: Scalar specifying position along surface_normal axis.
|
||||||
:param sample_period: Period for down-sampling the image. Default 1 (disabled)
|
which_shifts: Which grid to display. Default is the first grid (0).
|
||||||
:return Array containing the portion of the grid.
|
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):
|
if not is_scalar(center) and numpy.isreal(center):
|
||||||
raise GridError('center must be a real scalar')
|
raise GridError('center must be a real scalar')
|
||||||
@ -77,22 +80,24 @@ def get_slice(self,
|
|||||||
|
|
||||||
|
|
||||||
def visualize_slice(self,
|
def visualize_slice(self,
|
||||||
surface_normal: Direction or int,
|
surface_normal: Union[Direction, int],
|
||||||
center: float,
|
center: float,
|
||||||
which_shifts: int = 0,
|
which_shifts: int = 0,
|
||||||
sample_period: int = 1,
|
sample_period: int = 1,
|
||||||
finalize: bool = True,
|
finalize: bool = True,
|
||||||
pcolormesh_args: Dict = None):
|
pcolormesh_args: Optional[Dict[str, Any]] = None,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Visualize a slice of a grid.
|
Visualize a slice of a grid.
|
||||||
Interpolates if given a position between two planes.
|
Interpolates if given a position between two planes.
|
||||||
|
|
||||||
:param surface_normal: Axis normal to the plane we're displaying. Can be a Direction or
|
Args:
|
||||||
integer in range(3)
|
surface_normal: Axis normal to the plane we're displaying. Can be a `Direction` or
|
||||||
:param center: Scalar specifying position along surface_normal axis.
|
integer in `range(3)`
|
||||||
:param which_shifts: Which grid to display. Default is the first grid (0).
|
center: Scalar specifying position along surface_normal axis.
|
||||||
:param sample_period: Period for down-sampling the image. Default 1 (disabled)
|
which_shifts: Which grid to display. Default is the first grid (0).
|
||||||
:param finalize: Whether to call pyplot.show() after constructing the plot. Default True
|
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
|
from matplotlib import pyplot
|
||||||
|
|
||||||
@ -125,19 +130,21 @@ def visualize_slice(self,
|
|||||||
|
|
||||||
|
|
||||||
def visualize_isosurface(self,
|
def visualize_isosurface(self,
|
||||||
level: float = None,
|
level: Optional[float] = None,
|
||||||
which_shifts: int = 0,
|
which_shifts: int = 0,
|
||||||
sample_period: int = 1,
|
sample_period: int = 1,
|
||||||
show_edges: bool = True,
|
show_edges: bool = True,
|
||||||
finalize: bool = True):
|
finalize: bool = True,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Draw an isosurface plot of the device.
|
Draw an isosurface plot of the device.
|
||||||
|
|
||||||
:param level: Value at which to find isosurface. Default (None) uses mean value in grid.
|
Args:
|
||||||
:param which_shifts: Which grid to display. Default is the first grid (0).
|
level: Value at which to find isosurface. Default (None) uses mean value in grid.
|
||||||
:param sample_period: Period for down-sampling the image. Default 1 (disabled)
|
which_shifts: Which grid to display. Default is the first grid (0).
|
||||||
:param show_edges: Whether to draw triangle edges. Default True
|
sample_period: Period for down-sampling the image. Default 1 (disabled)
|
||||||
:param finalize: Whether to call pyplot.show() after constructing the plot. Default True
|
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
|
from matplotlib import pyplot
|
||||||
import skimage.measure
|
import skimage.measure
|
||||||
|
Loading…
Reference in New Issue
Block a user