general cleanup and typing fixes

This commit is contained in:
Jan Petykiewicz 2021-01-08 22:58:36 -08:00
parent db9e7831b9
commit f486209950
3 changed files with 49 additions and 39 deletions

View File

@ -44,6 +44,7 @@ def draw_polygons(self,
# Turn surface_normal into its integer representation # Turn surface_normal into its integer representation
if isinstance(surface_normal, Direction): if isinstance(surface_normal, Direction):
surface_normal = surface_normal.value surface_normal = surface_normal.value
assert(isinstance(surface_normal, int))
if surface_normal not in range(3): if surface_normal not in range(3):
raise GridError('Invalid surface_normal direction') raise GridError('Invalid surface_normal direction')
@ -96,8 +97,13 @@ def draw_polygons(self,
# 3) Adjust polygons for center # 3) Adjust polygons for center
polygons = [poly + center[surface] for poly in polygons] polygons = [poly + center[surface] for poly in polygons]
# ## Generate weighing function
def to_3d(vector: numpy.ndarray, val: float = 0.0) -> numpy.ndarray:
v_2d = numpy.array(vector, dtype=float)
return numpy.insert(v_2d, surface_normal, (val,))
# iterate over grids # iterate over grids
for (i, grid) in enumerate(self.grids): for i, grid in enumerate(self.grids):
# ## Evaluate or expand eps[i] # ## Evaluate or expand eps[i]
if callable(eps[i]): if callable(eps[i]):
# meshgrid over the (shifted) domain # meshgrid over the (shifted) domain
@ -105,17 +111,14 @@ def draw_polygons(self,
(x0, y0, z0) = numpy.meshgrid(*domain, indexing='ij') (x0, y0, z0) = numpy.meshgrid(*domain, indexing='ij')
# evaluate on the meshgrid # evaluate on the meshgrid
eps[i] = eps[i](x0, y0, z0) eps_i = eps[i](x0, y0, z0)
if not numpy.isfinite(eps[i]).all(): if not numpy.isfinite(eps_i).all():
raise GridError('Non-finite values in eps[%u]' % i) raise GridError('Non-finite values in eps[%u]' % i)
elif not is_scalar(eps[i]): elif not is_scalar(eps[i]):
raise GridError('Unsupported eps[{}]: {}'.format(i, type(eps[i]))) raise GridError('Unsupported eps[{}]: {}'.format(i, type(eps[i])))
# do nothing if eps[i] is scalar non-callable else:
# eps[i] is scalar non-callable
# ## Generate weighing function eps_i = eps[i]
def to_3d(vector: List or numpy.ndarray, val: float=0.0):
v_2d = numpy.array(vector, dtype=float)
return numpy.insert(v_2d, surface_normal, (val,))
w_xy = zeros((bdi_max - bdi_min + 1)[surface].astype(int)) w_xy = zeros((bdi_max - bdi_min + 1)[surface].astype(int))
@ -183,7 +186,7 @@ def draw_polygons(self,
# ## Modify the grid # ## Modify the grid
g_slice = (i,) + tuple(numpy.s_[bdi_min[a]:bdi_max[a] + 1] for a in range(3)) g_slice = (i,) + tuple(numpy.s_[bdi_min[a]:bdi_max[a] + 1] for a in range(3))
self.grids[g_slice] = (1 - w) * self.grids[g_slice] + w * eps[i] self.grids[g_slice] = (1 - w) * self.grids[g_slice] + w * eps_i
def draw_polygon(self, def draw_polygon(self,
@ -327,11 +330,9 @@ def draw_extrude_rectangle(self,
# Turn extrude_direction into its integer representation # Turn extrude_direction into its integer representation
if isinstance(direction, Direction): if isinstance(direction, Direction):
direction = direction.value direction = direction.value
if abs(direction) not in range(3): assert(isinstance(direction, int))
raise GridError('Invalid extrude_direction')
s = numpy.sign(polarity) s = numpy.sign(polarity)
surface = numpy.delete(range(3), direction)
rectangle = numpy.array(rectangle, dtype=float) rectangle = numpy.array(rectangle, dtype=float)
if s == 0: if s == 0:
@ -344,12 +345,14 @@ def draw_extrude_rectangle(self,
center = rectangle.sum(axis=0) / 2.0 center = rectangle.sum(axis=0) / 2.0
center[direction] += s * distance / 2.0 center[direction] += s * distance / 2.0
surface = numpy.delete(range(3), direction)
dim = numpy.fabs(diff(rectangle, axis=0).T)[surface] dim = numpy.fabs(diff(rectangle, axis=0).T)[surface]
p = numpy.vstack((numpy.array([-1, -1, 1, 1], dtype=float) * dim[0]/2.0, p = numpy.vstack((numpy.array([-1, -1, 1, 1], dtype=float) * dim[0]/2.0,
numpy.array([-1, 1, 1, -1], dtype=float) * dim[1]/2.0)).T numpy.array([-1, 1, 1, -1], dtype=float) * dim[1]/2.0)).T
thickness = distance thickness = distance
eps_func = [None] * len(self.grids) eps_func = []
for i, grid in enumerate(self.grids): for i, grid in enumerate(self.grids):
z = self.pos2ind(rectangle[0, :], i, round_ind=False, check_bounds=False)[direction] z = self.pos2ind(rectangle[0, :], i, round_ind=False, check_bounds=False)[direction]
@ -367,10 +370,10 @@ def draw_extrude_rectangle(self,
xyzi = numpy.array([self.pos2ind(qrs, which_shifts=i) xyzi = numpy.array([self.pos2ind(qrs, which_shifts=i)
for qrs in zip(xs.flat, ys.flat, zs.flat)], dtype=int) for qrs in zip(xs.flat, ys.flat, zs.flat)], dtype=int)
# reshape to original shape and keep only in-plane components # reshape to original shape and keep only in-plane components
(qi, ri) = [numpy.reshape(xyzi[:, k], xs.shape) for k in surface] qi, ri = (numpy.reshape(xyzi[:, k], xs.shape) for k in surface)
return eps[qi, ri] return eps[qi, ri]
eps_func[i] = f_eps eps_func.append(f_eps)
self.draw_polygon(direction, center, p, thickness, eps_func) self.draw_polygon(direction, center, p, thickness, eps_func)

View File

@ -16,7 +16,7 @@ __author__ = 'Jan Petykiewicz'
eps_callable_type = Callable[[numpy.ndarray, numpy.ndarray, numpy.ndarray], numpy.ndarray] eps_callable_type = Callable[[numpy.ndarray, numpy.ndarray, numpy.ndarray], numpy.ndarray]
class Grid(object): class Grid:
""" """
Simulation grid generator intended for electromagnetic simulations. Simulation grid generator intended for electromagnetic simulations.
Can be used to generate non-uniform rectangular grids (the entire grid Can be used to generate non-uniform rectangular grids (the entire grid
@ -44,19 +44,32 @@ class Grid(object):
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.
""" """
exyz: List[numpy.ndarray]
"""Cell edges. Monotonically increasing without duplicates."""
Yee_Shifts_E = 0.5 * numpy.array([[1, 0, 0], grids: numpy.ndarray
"""epsilon (or mu, or whatever) grids. shape is (num_grids, X, Y, Z)"""
periodic: List[bool]
"""For each axis, determines how far the rightmost boundary gets shifted. """
shifts: numpy.ndarray
"""Offsets `[[x0, y0, z0], [x1, y1, z1], ...]` for grid `0,1,...`"""
Yee_Shifts_E: ClassVar[numpy.ndarray] = 0.5 * numpy.array([[1, 0, 0],
[0, 1, 0], [0, 1, 0],
[0, 0, 1]], dtype=float) # type: numpy.ndarray [0, 0, 1]], dtype=float)
"""Default shifts for Yee grid E-field""" """Default shifts for Yee grid E-field"""
Yee_Shifts_H = 0.5 * numpy.array([[0, 1, 1], Yee_Shifts_H: ClassVar[numpy.ndarray] = 0.5 * numpy.array([[0, 1, 1],
[1, 0, 1], [1, 0, 1],
[1, 1, 0]], dtype=float) # type: numpy.ndarray [1, 1, 0]], dtype=float)
"""Default shifts for Yee grid H-field""" """Default shifts for Yee grid H-field"""
from .draw import draw_polygons, draw_polygon, draw_slab, draw_cuboid, \ from .draw import (
draw_cylinder, draw_extrude_rectangle draw_polygons, draw_polygon, draw_slab, draw_cuboid,
draw_cylinder, draw_extrude_rectangle,
)
from .read import get_slice, visualize_slice, visualize_isosurface from .read import get_slice, visualize_slice, visualize_isosurface
from .position import ind2pos, pos2ind from .position import ind2pos, pos2ind
@ -237,23 +250,17 @@ class Grid(object):
Raises: Raises:
`GridError` on invalid input `GridError` on invalid input
""" """
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)]
"""Cell edges. Monotonically increasing without duplicates.""" self.shifts = numpy.array(shifts, dtype=float)
self.grids = None # type: numpy.ndarray
"""epsilon (or mu, or whatever) grids. shape is (num_grids, X, Y, Z)"""
for i in range(3): for i in range(3):
if len(self.exyz[i]) != len(pixel_edge_coordinates[i]): if len(self.exyz[i]) != len(pixel_edge_coordinates[i]):
warnings.warn('Dimension {} had duplicate edge coordinates'.format(i), stacklevel=2) warnings.warn('Dimension {} had duplicate edge coordinates'.format(i), stacklevel=2)
if is_scalar(periodic): if isinstance(periodic, bool):
periodic = [periodic] * 3 self.periodic = [periodic] * 3
self.periodic = periodic # type: List[bool] else:
"""For each axis, determines how far the rightmost boundary gets shifted. """ self.periodic = list(periodic)
self.shifts = numpy.array(shifts, dtype=float) # type: numpy.ndarray
"""Offsets `[[x0, y0, z0], [x1, y1, z1], ...]` for grid `0,1,...`"""
if len(self.shifts.shape) != 2: if len(self.shifts.shape) != 2:
raise GridError('Misshapen shifts: shifts must have two axes! ' raise GridError('Misshapen shifts: shifts must have two axes! '
@ -276,7 +283,7 @@ class Grid(object):
raise GridError('Number of grids exceeds number of shifts (%u)' % num_shifts) raise GridError('Number of grids exceeds number of shifts (%u)' % num_shifts)
grids_shape = hstack((num_grids, self.shape)) grids_shape = hstack((num_grids, self.shape))
if is_scalar(initial): if isinstance(initial, (float, int)):
if isinstance(initial, int): if isinstance(initial, int):
warnings.warn('Initial value is an int, grids will be integer-typed!', stacklevel=2) warnings.warn('Initial value is an int, grids will be integer-typed!', stacklevel=2)
self.grids = numpy.full(grids_shape, initial) self.grids = numpy.full(grids_shape, initial)

View File

@ -42,7 +42,7 @@ def ind2pos(self,
if check_bounds: if check_bounds:
if round_ind: if round_ind:
low_bound = 0.0 low_bound = 0.0
high_bound = -1 high_bound = -1.0
else: else:
low_bound = -0.5 low_bound = -0.5
high_bound = -0.5 high_bound = -0.5