class SquareImplant(ProsthesisSystem): def __init__(self, e_num_side, e_radius, spacing=None, side_size=None, stim=None, eye='RE', name=None): """ e_num_side : the number of electrodes in the squares implant's side e_radius : the radius of each electrode in the square implant [microns] spacing : the spacing between to electrodes in the squares implant's [microns] side_size : the size of the squares implant's side in [microns] stim : stimuli signal for each electrode [one dimensional array] eye : the eye where it is implanted ['RE', 'LE'] name : name of the implant [string] """ # if there is no name assigned the derive it from the desired characteristics of the implant if name is None: self.name = f"e_num_side={e_num_side}-e_radius={e_radius}-spacing={spacing}-side_size={side_size}" else: self.name = name # if side size is set the derive the spacing between each electrod from it if side_size is not None: spacing = (side_size - 2 * e_radius) / (e_num_side - 1) elif spacing is None: raise Exception( "Provide a 'spacing' or 'side_size' parameter in microns") if spacing < 2 * e_radius: warnings.warn( 'Either the electrode radius (e_radius) is too big or the side size (side_size) ' + 'is too small and there is electrode overlap', stacklevel=2) self.earray = ElectrodeGrid((e_num_side, e_num_side), x=0, y=0, z=0, rot=0, r=e_radius, spacing=spacing, etype=DiskElectrode, names=('A', '1')) self.stim = stim self.eye = eye # plot implant on an axon map def plot_on_axon_map(self, annotate_implant=False, annotate_quadrants=True, ax=None): if ax is None: _, ax = plt.subplots(figsize=(10, 10)) AxonMapModel().plot(annotate=annotate_quadrants, ax=ax) self.earray.plot(annotate=annotate_implant, ax=ax)
def __init__(self, e_num_side, e_radius, spacing=None, side_size=None, stim=None, eye='RE', name=None): """ e_num_side : the number of electrodes in the squares implant's side e_radius : the radius of each electrode in the square implant [microns] spacing : the spacing between to electrodes in the squares implant's [microns] side_size : the size of the squares implant's side in [microns] stim : stimuli signal for each electrode [one dimensional array] eye : the eye where it is implanted ['RE', 'LE'] name : name of the implant [string] """ # if there is no name assigned the derive it from the desired characteristics of the implant if name is None: self.name = f"e_num_side={e_num_side}-e_radius={e_radius}-spacing={spacing}-side_size={side_size}" else: self.name = name # if side size is set the derive the spacing between each electrod from it if side_size is not None: spacing = (side_size - 2 * e_radius) / (e_num_side - 1) elif spacing is None: raise Exception( "Provide a 'spacing' or 'side_size' parameter in microns") if spacing < 2 * e_radius: warnings.warn( 'Either the electrode radius (e_radius) is too big or the side size (side_size) ' + 'is too small and there is electrode overlap', stacklevel=2) self.earray = ElectrodeGrid((e_num_side, e_num_side), x=0, y=0, z=0, rot=0, r=e_radius, spacing=spacing, etype=DiskElectrode, names=('A', '1')) self.stim = stim self.eye = eye
def test_ProsthesisSystem_reshape_stim(rot, gtype, n_frames): implant = ProsthesisSystem(ElectrodeGrid((10, 10), 30, rot=rot, type=gtype)) # Smoke test the automatic reshaping: n_px = 21 implant.stim = ImageStimulus(np.ones((n_px, n_px, n_frames)).squeeze()) npt.assert_equal(implant.stim.data.shape, (implant.n_electrodes, 1)) npt.assert_equal(implant.stim.time, None) implant.stim = VideoStimulus(np.ones((n_px, n_px, 3 * n_frames)), time=2 * np.arange(3 * n_frames)) npt.assert_equal(implant.stim.data.shape, (implant.n_electrodes, 3 * n_frames)) npt.assert_equal(implant.stim.time, 2 * np.arange(3 * n_frames)) # Verify that a horizontal stimulus will always appear horizontally, even if # the device is rotated: data = np.zeros((50, 50)) data[20:-20, 10:-10] = 1 implant.stim = ImageStimulus(data) model = ScoreboardModel(xrange=(-1, 1), yrange=(-1, 1), rho=30, xystep=0.02) model.build() percept = label(model.predict_percept(implant).data.squeeze().T > 0.2) npt.assert_almost_equal(regionprops(percept)[0].orientation, 0, decimal=1)
def test_ProsthesisSystem_deactivate(): implant = ProsthesisSystem(ElectrodeGrid((10, 10), 30)) implant.stim = np.ones(implant.n_electrodes) electrode = 'A3' npt.assert_equal(electrode in implant.stim.electrodes, True) implant.deactivate(electrode) npt.assert_equal(implant[electrode].activated, False) npt.assert_equal(electrode in implant.stim.electrodes, False)
def test_ElectrodeGrid___get_item__(): grid = ElectrodeGrid((2, 4), names=('C', '3')) npt.assert_equal(grid[0], grid['C3']) npt.assert_equal(grid[0, 0], grid['C3']) npt.assert_equal(grid[1], grid['C4']) npt.assert_equal(grid[0, 1], grid['C4']) npt.assert_equal(grid[['C3', 1, (0, 2)]], [grid['C3'], grid['C4'], grid['C5']])
def test_ElectrodeGrid___get_item__(gtype): grid = ElectrodeGrid((2, 4), 20, names=('A', '1'), type=gtype, etype=DiskElectrode, r=20) npt.assert_equal(grid[0], grid['A1']) npt.assert_equal(grid[0, 0], grid['A1']) npt.assert_equal(grid[1], grid['A2']) npt.assert_equal(grid[0, 1], grid['A2']) npt.assert_equal(grid[['A1', 1, (0, 2)]], [grid['A1'], grid['A2'], grid['A3']])
def test_ProsthesisSystem_stim(): implant = ProsthesisSystem(ElectrodeGrid((13, 13), 20)) stim = Stimulus(np.ones((13 * 13 + 1, 5))) with pytest.raises(ValueError): implant.stim = stim # Deactivated electrodes cannot receive stimuli: implant.deactivate('H4') npt.assert_equal(implant['H4'].activated, False) implant.stim = {'H4': 1} npt.assert_equal('H4' in implant.stim.electrodes, False) implant.deactivate('all') npt.assert_equal(not implant.stim.data, True) implant.activate('all') implant.stim = {'H4': 1} npt.assert_equal('H4' in implant.stim.electrodes, True)
def test_ProsthesisSystem_stim(): implant = ProsthesisSystem(ElectrodeGrid((13, 13), 20)) stim = Stimulus(np.ones((13 * 13 + 1, 5))) with pytest.raises(ValueError): implant.stim = stim # color mapping stim = np.zeros((13 * 13, 5)) stim[84, 0] = 1 stim[98, 2] = 2 implant.stim = stim plt.cla() ax = implant.plot(stim_cmap='hsv') plt.colorbar() npt.assert_equal(len(ax.collections), 1) npt.assert_equal(ax.collections[0].colorbar.vmax, 2) npt.assert_equal(ax.collections[0].cmap(ax.collections[0].norm(1)), (0.0, 1.0, 0.9647031631761764, 1)) # make sure default behaviour unchanged plt.cla() ax = implant.plot() plt.colorbar() npt.assert_equal(len(ax.collections), 1) npt.assert_equal(ax.collections[0].colorbar.vmax, 1) npt.assert_equal(ax.collections[0].cmap(ax.collections[0].norm(1)), (0.993248, 0.906157, 0.143936, 1)) # Deactivated electrodes cannot receive stimuli: implant.deactivate('H4') npt.assert_equal(implant['H4'].activated, False) implant.stim = {'H4': 1} npt.assert_equal('H4' in implant.stim.electrodes, False) implant.deactivate('all') npt.assert_equal(not implant.stim.data, True) implant.activate('all') implant.stim = {'H4': 1} npt.assert_equal('H4' in implant.stim.electrodes, True)
- An electrode type ``etype``, which must be a subclass of :py:class:`~pulse2percept.implants.Electrode`. By default, :py:class:`~pulse2percept.implants.PointSource` is chosen. - Any additional parameters that should be passed to the :py:class:`~pulse2percept.implants.Electrode` constructor, such as a radius ``r`` for :py:class:`~pulse2percept.implants.DiskElectrode`. Let's say we want to create a 2x3 rectangular grid of :py:class:`~pulse2percept.implants.PointSource` objects, each electrode spaced 500 microns apart, and the whole grid should be centered over the fovea: """ # sphinx_gallery_thumbnail_number = 3 from pulse2percept.implants import ElectrodeGrid grid = ElectrodeGrid((2, 3), 500) ############################################################################## # We can access individual electrodes by indexing into ``grid``: # # The first electrode: grid[0] ############################################################################## # The first electrode by name: grid['A1'] ############################################################################## # Accessing the x-coordinate of the first electrode:
def test_ElectrodeGrid_get_params(gtype): # When the electrode_type is 'DiskElectrode' # test the default value egrid = ElectrodeGrid((2, 3), 40, type=gtype, etype=DiskElectrode, r=20) npt.assert_equal(egrid.shape, (2, 3)) npt.assert_equal(egrid.type, gtype)
def test_ElectrodeGrid(gtype): # Must pass in tuple/list of (rows, cols) for grid shape: with pytest.raises(TypeError): ElectrodeGrid("badinstantiation") with pytest.raises(TypeError): ElectrodeGrid(OrderedDict({'badinstantiation': 0})) with pytest.raises(ValueError): ElectrodeGrid([0], 10) with pytest.raises(ValueError): ElectrodeGrid([1, 2, 3], 10) with pytest.raises(TypeError): ElectrodeGrid({'1': 2}, 10) # Must pass in valid Electrode type: with pytest.raises(TypeError): ElectrodeGrid((2, 3), 10, type=gtype, etype=ElectrodeArray) with pytest.raises(TypeError): ElectrodeGrid((2, 3), 10, type=gtype, etype="foo") # Must pass in valid Orientation value: with pytest.raises(ValueError): ElectrodeGrid((2, 3), 10, type=gtype, orientation="foo") with pytest.raises(TypeError): ElectrodeGrid((2, 3), 10, type=gtype, orientation=False) # Must pass in radius `r` for grid of DiskElectrode objects: gshape = (4, 5) spacing = 100 grid = ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, r=13) for e in grid.values(): npt.assert_almost_equal(e.r, 13) grid = ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, r=np.arange(1, np.prod(gshape) + 1)) for i, e in enumerate(grid.values()): npt.assert_almost_equal(e.r, i + 1) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, radius=10) # Number of radii must match number of electrodes with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, radius=[2, 13, 14]) # Only DiskElectrode needs r, not PointSource: with pytest.raises(TypeError): ElectrodeGrid(gshape, spacing, type=gtype, r=10) # Must pass in radius `r` for grid of DiskElectrode objects: gshape = (4, 5) spacing = 100 with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, radius=10) # Number of radii must match number of electrodes with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, radius=[2, 13]) # Must pass in valid grid type: with pytest.raises(TypeError): ElectrodeGrid(gshape, spacing, type=DiskElectrode) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type='unknown') # Verify spacing is correct: grid = ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, r=30) npt.assert_almost_equal(np.sqrt((grid['A1'].x - grid['A2'].x) ** 2 + (grid['A1'].y - grid['A2'].y) ** 2), spacing) npt.assert_almost_equal(np.sqrt((grid['A1'].x - grid['B1'].x) ** 2 + (grid['A1'].y - grid['B1'].y) ** 2), spacing) grid = ElectrodeGrid(gshape, spacing, type=gtype, orientation='vertical', etype=DiskElectrode, r=30) npt.assert_almost_equal(np.sqrt((grid['B1'].x - grid['B2'].x) ** 2 + (grid['B1'].y - grid['B2'].y) ** 2), spacing) npt.assert_almost_equal(np.sqrt((grid['A1'].x - grid['B1'].x) ** 2 + (grid['A1'].y - grid['B1'].y) ** 2), spacing) # A valid 2x5 grid centered at (0, 500): x, y = 0, 500 radius = 30 egrid = ElectrodeGrid(gshape, spacing, x=x, y=y, type='rect', etype=DiskElectrode, r=radius) npt.assert_equal(egrid.shape, gshape) npt.assert_equal(egrid.n_electrodes, np.prod(gshape)) # Make sure different electrodes have different coordinates: npt.assert_equal(len(np.unique([e.x for e in egrid.values()])), gshape[1]) npt.assert_equal(len(np.unique([e.y for e in egrid.values()])), gshape[0]) # Make sure the average of all x-coordinates == x: # (Note: egrid has all electrodes in a dictionary, with (name, object) # as (key, value) pairs. You can get the electrode names by iterating over # egrid.keys(). You can get the electrode objects by iterating over # egrid.values().) npt.assert_almost_equal(np.mean([e.x for e in egrid.values()]), x) # Same for y: npt.assert_almost_equal(np.mean([e.y for e in egrid.values()]), y) # Test whether egrid.z is set correctly, when z is a constant: z = 12 egrid = ElectrodeGrid(gshape, spacing, z=z, type=gtype, etype=DiskElectrode, r=radius) for i in egrid.values(): npt.assert_equal(i.z, z) # and when every electrode has a different z: z = np.arange(np.prod(gshape)) egrid = ElectrodeGrid(gshape, spacing, z=z, type=gtype, etype=DiskElectrode, r=radius) x = -1 for i in egrid.values(): npt.assert_equal(i.z, x + 1) x = i.z # TODO display a warning when rot > 2pi (meaning it might be in degrees). # I think we did this somewhere in the old Argus code # TODO test rotation, making sure positive angles rotate CCW egrid1 = ElectrodeGrid((2, 2), spacing, type=gtype, etype=DiskElectrode, r=radius) egrid2 = ElectrodeGrid((2, 2), spacing, rot=np.deg2rad(10), type=gtype, etype=DiskElectrode, r=radius) npt.assert_equal(egrid1["A1"].x < egrid2["A1"].x, True) npt.assert_equal(egrid1["A1"].y > egrid2["A1"].y, True) npt.assert_equal(egrid1["B2"].x > egrid2["B2"].x, True) npt.assert_equal(egrid1["B2"].y < egrid2["B2"].y, True) # Smallest possible grid: egrid = ElectrodeGrid((1, 1), spacing, type=gtype, etype=DiskElectrode, r=radius) npt.assert_equal(egrid.shape, (1, 1)) npt.assert_equal(egrid.n_electrodes, 1) # Grid has same size as 'names': egrid = ElectrodeGrid((1, 2), spacing, type=gtype, names=('C1', '4')) npt.assert_equal(egrid[0, 0], egrid['C1']) npt.assert_equal(egrid[0, 1], egrid['4']) # Can't have a zero-sized grid: with pytest.raises(ValueError): egrid = ElectrodeGrid((0, 0), spacing, type=gtype) with pytest.raises(ValueError): egrid = ElectrodeGrid((5, 0), spacing, type=gtype) # Invalid naming conventions: with pytest.raises(ValueError): egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=[1]) with pytest.raises(ValueError): egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=[]) with pytest.raises(TypeError): egrid = ElectrodeGrid(gshape, spacing, type=gtype, names={1}) with pytest.raises(TypeError): egrid = ElectrodeGrid(gshape, spacing, type=gtype, names={}) with pytest.raises(TypeError): ElectrodeGrid(gshape, spacing, names={'1': 2}) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, names=('A', '1', 'A')) with pytest.raises(TypeError): ElectrodeGrid(gshape, spacing, names=(1, 'A')) with pytest.raises(TypeError): ElectrodeGrid(gshape, spacing, names=('A', 1)) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, names=('A', '~')) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, names=('~', 'A')) # Test all naming conventions: gshape = (2, 3) egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('A', '1')) # print([e for e in egrid.keys()]) npt.assert_equal([e for e in egrid.keys()], ['A1', 'A2', 'A3', 'B1', 'B2', 'B3']) egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('1', 'A')) # print([e for e in egrid.keys()]) # egrid = ElectrodeGrid(shape, names=('A', '1')) npt.assert_equal([e for e in egrid.keys()], ['A1', 'B1', 'C1', 'A2', 'B2', 'C2']) egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('1', '1')) # print([e for e in egrid.keys()]) npt.assert_equal([e for e in egrid.keys()], ['11', '12', '13', '21', '22', '23']) egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('A', 'A')) # print([e for e in egrid.keys()]) npt.assert_equal([e for e in egrid.keys()], ['AA', 'AB', 'AC', 'BA', 'BB', 'BC']) # Still starts at A: egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('B', '1')) npt.assert_equal([e for e in egrid.keys()], ['A1', 'A2', 'A3', 'B1', 'B2', 'B3']) egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('A', '2')) npt.assert_equal([e for e in egrid.keys()], ['A1', 'A2', 'A3', 'B1', 'B2', 'B3']) # test unique names egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=['53', '18', '00', '81', '11', '12']) npt.assert_equal([e for e in egrid.keys()], ['53', '18', '00', '81', '11', '12']) # Slots: npt.assert_equal(hasattr(egrid, '__slots__'), True) npt.assert_equal(hasattr(egrid, '__dict__'), False)
- Any additional parameters that should be passed to the :py:class:`~pulse2percept.implants.Electrode` constructor, such as a radius ``r`` for :py:class:`~pulse2percept.implants.DiskElectrode`. Let's say we want to create a 2x3 rectangular grid of :py:class:`~pulse2percept.implants.PointSource` objects, each electrode spaced 500 microns apart, and the whole grid should be centered over the fovea: """ # sphinx_gallery_thumbnail_number = 3 from pulse2percept.models import AxonMapModel from numpy import pi from pulse2percept.implants import DiskElectrode from pulse2percept.implants import ElectrodeGrid grid = ElectrodeGrid((2, 3), 500) ############################################################################## # We can access individual electrodes by indexing into ``grid``: # # The first electrode: grid[0] ############################################################################## # The first electrode by name: grid['A1'] ############################################################################## # Accessing the x-coordinate of the first electrode:
def test_ElectrodeGrid(): # Must pass in tuple/list of (rows, cols) for grid shape: with pytest.raises(TypeError): ElectrodeGrid("badinstantiation") with pytest.raises(TypeError): ElectrodeGrid(coll.OrderedDict({'badinstantiation': 0})) with pytest.raises(ValueError): ElectrodeGrid([0]) with pytest.raises(ValueError): ElectrodeGrid([1, 2, 3]) with pytest.raises(TypeError): ElectrodeGrid((2, 3), etype=ElectrodeArray) with pytest.raises(TypeError): ElectrodeGrid((2, 3), etype="foo") # A valid 2x5 grid centered at (0, 500): shape = (2, 3) x, y = 0, 500 spacing = 100 egrid = ElectrodeGrid(shape, x=x, y=y, spacing=spacing) npt.assert_equal(egrid.shape, shape) npt.assert_equal(egrid.n_electrodes, np.prod(shape)) npt.assert_equal(egrid.x, x) npt.assert_equal(egrid.y, y) npt.assert_almost_equal(egrid.spacing, spacing) # Make sure different electrodes have different coordinates: npt.assert_equal(len(np.unique([e.x for e in egrid.values()])), shape[1]) npt.assert_equal(len(np.unique([e.y for e in egrid.values()])), shape[0]) # Make sure the average of all x-coordinates == x: # (Note: egrid has all electrodes in a dictionary, with (name, object) # as (key, value) pairs. You can get the electrode names by iterating over # egrid.keys(). You can get the electrode objects by iterating over # egrid.values().) npt.assert_almost_equal(np.mean([e.x for e in egrid.values()]), x) # Same for y: npt.assert_almost_equal(np.mean([e.y for e in egrid.values()]), y) # Test whether egrid.z is set correctly, when z is a constant: z = 12 egrid = ElectrodeGrid(shape, z=z) npt.assert_equal(egrid.z, z) for i in egrid.values(): npt.assert_equal(i.z, z) # and when every electrode has a different z: z = np.arange(np.prod(shape)) egrid = ElectrodeGrid(shape, z=z) npt.assert_equal(egrid.z, z) x = -1 for i in egrid.values(): npt.assert_equal(i.z, x + 1) x = i.z # TODO display a warning when rot > 2pi (meaning it might be in degrees). # I think we did this somewhere in the old Argus code # TODO test rotation, making sure positive angles rotate CCW egrid1 = ElectrodeGrid(shape=(2, 2)) egrid2 = ElectrodeGrid(shape=(2, 2), rot=np.deg2rad(10)) npt.assert_equal(egrid1["A1"].x < egrid2["A1"].x, True) npt.assert_equal(egrid1["A1"].y > egrid2["A1"].y, True) npt.assert_equal(egrid1["B2"].x > egrid2["B2"].x, True) npt.assert_equal(egrid1["B2"].y < egrid2["B2"].y, True) # Smallest possible grid: egrid = ElectrodeGrid((1, 1)) npt.assert_equal(egrid.shape, (1, 1)) npt.assert_equal(egrid.n_electrodes, 1) # Can't have a zero-sized grid: with pytest.raises(ValueError): egrid = ElectrodeGrid((0, 0)) with pytest.raises(ValueError): egrid = ElectrodeGrid((5, 0)) # Invalid naming conventions: with pytest.raises(ValueError): egrid = ElectrodeGrid(shape, names=[1]) with pytest.raises(ValueError): egrid = ElectrodeGrid(shape, names=[]) with pytest.raises(TypeError): egrid = ElectrodeGrid(shape, names={1}) with pytest.raises(TypeError): egrid = ElectrodeGrid(shape, names={}) # Test all naming conventions: egrid = ElectrodeGrid(shape, names=('A', '1')) # print([e for e in egrid.keys()]) npt.assert_equal([e for e in egrid.keys()], ['A1', 'A2', 'A3', 'B1', 'B2', 'B3']) egrid = ElectrodeGrid(shape, names=('1', 'A')) # print([e for e in egrid.keys()]) # egrid = ElectrodeGrid(shape, names=('A', '1')) npt.assert_equal([e for e in egrid.keys()], ['A1', 'B1', 'C1', 'A2', 'B2', 'C2']) # egrid = ElectrodeGrid(shape, names=('A', '1')) # npt.assert_equal([e for e in egrid.keys()], # ['A1', 'A1', 'C1', 'A2', 'B2', 'C2']) egrid = ElectrodeGrid(shape, names=('1', '1')) # print([e for e in egrid.keys()]) npt.assert_equal([e for e in egrid.keys()], ['11', '12', '13', '21', '22', '23']) egrid = ElectrodeGrid(shape, names=('A', 'A')) # print([e for e in egrid.keys()]) npt.assert_equal([e for e in egrid.keys()], ['AA', 'AB', 'AC', 'BA', 'BB', 'BC']) # rows and columns start at values other than A or 1 egrid = ElectrodeGrid(shape, names=('B', '1')) npt.assert_equal([e for e in egrid.keys()], ['B1', 'B2', 'B3', 'C1', 'C2', 'C3']) egrid = ElectrodeGrid(shape, names=('A', '2')) npt.assert_equal([e for e in egrid.keys()], ['A2', 'A3', 'A4', 'B2', 'B3', 'B4']) # test unique names egrid = ElectrodeGrid(shape, names=['53', '18', '00', '81', '11', '12']) npt.assert_equal([e for e in egrid.keys()], ['53', '18', '00', '81', '11', '12'])
def test_ElectrodeGrid_get_params(): # When the electrode_type is 'DiskElectrode' # test the default value egrid = ElectrodeGrid((2, 3), 40, etype=DiskElectrode, r=20) params = { 'shape': (2, 3), 'x': 0, 'y': 0, 'z': 0, 'etype': DiskElectrode, 'rot': 0, 'spacing': 40, 'name_cols': '1', 'name_rows': 'A', 'r': 20 } npt.assert_equal(egrid.get_params(), params) # test the nondefault value for all the parameters egrid = ElectrodeGrid((2, 3), 30, x=10, y=20, z=30, rot=10, names=('A', '1'), etype=DiskElectrode, r=20) params = { 'shape': (2, 3), 'x': 10, 'y': 20, 'z': 30, 'rot': 10, 'spacing': 30, 'name_cols': '1', 'name_rows': 'A', 'etype': DiskElectrode, 'r': 20 } npt.assert_equal(egrid.get_params(), params) # When the electrode_type is 'PointSource' # test the default value egrid = ElectrodeGrid((2, 3), 20, etype=PointSource) params = { 'shape': (2, 3), 'x': 0, 'y': 0, 'z': 0, 'etype': PointSource, 'rot': 0, 'spacing': 20, 'name_cols': '1', 'name_rows': 'A' } npt.assert_equal(egrid.get_params(), params) # test the nondefault value for all the parameters egrid = ElectrodeGrid((2, 3), 30, x=10, y=20, z=30, rot=10, names=('A', '1'), etype=PointSource) params = { 'shape': (2, 3), 'x': 10, 'y': 20, 'z': 30, 'rot': 10, 'spacing': 30, 'etype': PointSource, 'name_cols': '1', 'name_rows': 'A' } npt.assert_equal(egrid.get_params(), params)
def test_ElectrodeGrid__make_grid(gtype, orientation): # A valid 2x5 grid centered at (0, 500): x, y = 0, 500 radius = 30 gshape = (4, 6) spacing = 100 egrid = ElectrodeGrid(gshape, spacing, x=x, y=y, type='rect', r=radius, etype=DiskElectrode, orientation=orientation) npt.assert_equal(egrid.shape, gshape) npt.assert_equal(egrid.n_electrodes, np.prod(gshape)) # Make sure different electrodes have different coordinates: npt.assert_equal(len(np.unique([e.x for e in egrid.electrode_objects])), gshape[1]) npt.assert_equal(len(np.unique([e.y for e in egrid.electrode_objects])), gshape[0]) # Make sure the average of all x-coordinates == x: # (Note: egrid has all electrodes in a dictionary, with (name, object) # as (key, value) pairs. You can get the electrode names by iterating over # egrid.keys(). You can get the electrode objects by iterating over # egrid.values().) npt.assert_almost_equal(np.mean([e.x for e in egrid.electrode_objects]), x) # Same for y: npt.assert_almost_equal(np.mean([e.y for e in egrid.electrode_objects]), y) # Test whether egrid.z is set correctly, when z is a constant: z = 12 egrid = ElectrodeGrid(gshape, spacing, z=z, type=gtype, r=radius, etype=DiskElectrode, orientation=orientation) for i in egrid.electrode_objects: npt.assert_equal(i.z, z) # and when every electrode has a different z: z = np.arange(np.prod(gshape)) egrid = ElectrodeGrid(gshape, spacing, z=z, type=gtype, r=radius, etype=DiskElectrode, orientation=orientation) x = -1 for i in egrid.electrode_objects: npt.assert_equal(i.z, x + 1) x = i.z # TODO test rotation, making sure positive angles rotate CCW egrid1 = ElectrodeGrid((2, 2), spacing, type=gtype, etype=DiskElectrode, r=radius, orientation=orientation) egrid2 = ElectrodeGrid((2, 2), spacing, rot=10, type=gtype, r=radius, etype=DiskElectrode, orientation=orientation) npt.assert_equal(egrid1["A1"].x < egrid2["A1"].x, True) npt.assert_equal(egrid1["A1"].y > egrid2["A1"].y, True) npt.assert_equal(egrid1["B2"].x > egrid2["B2"].x, True) npt.assert_equal(egrid1["B2"].y < egrid2["B2"].y, True) # Smallest possible grid: egrid = ElectrodeGrid((1, 1), spacing, type=gtype, etype=DiskElectrode, r=radius, orientation=orientation) npt.assert_equal(egrid.shape, (1, 1)) npt.assert_equal(egrid.n_electrodes, 1) # Can't have a zero-sized grid: with pytest.raises(ValueError): egrid = ElectrodeGrid((0, 0), spacing, type=gtype) with pytest.raises(ValueError): egrid = ElectrodeGrid((5, 0), spacing, type=gtype) # Verify spacing is correct: grid = ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, r=30, orientation=orientation) npt.assert_almost_equal(np.sqrt((grid['A1'].x - grid['B1'].x) ** 2 + (grid['A1'].y - grid['B1'].y) ** 2), spacing) npt.assert_almost_equal(np.sqrt((grid['A1'].x - grid['A2'].x) ** 2 + (grid['A1'].y - grid['A2'].y) ** 2), spacing) if gtype == 'hex': npt.assert_almost_equal(np.sqrt((grid['A1'].x - grid['B2'].x) ** 2 + (grid['A1'].y - grid['B2'].y) ** 2), spacing) # Different spacing in x and y: x_spc, y_spc = 50, 100 grid = ElectrodeGrid(gshape, (x_spc, y_spc), type=gtype, r=30, etype=DiskElectrode, orientation=orientation) print(gtype, orientation) npt.assert_almost_equal(grid['A2'].x - grid['A1'].x, x_spc) npt.assert_almost_equal(grid['B2'].y - grid['A2'].y, y_spc) # Grid has same size as 'names': egrid = ElectrodeGrid((1, 2), spacing, type=gtype, names=('C1', '4')) npt.assert_equal(egrid[0, 0], egrid['C1']) npt.assert_equal(egrid[0, 1], egrid['4']) # Invalid naming conventions: with pytest.raises(ValueError): egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=[1]) with pytest.raises(ValueError): egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=[]) with pytest.raises(TypeError): egrid = ElectrodeGrid(gshape, spacing, type=gtype, names={1}) with pytest.raises(TypeError): egrid = ElectrodeGrid(gshape, spacing, type=gtype, names={}) with pytest.raises(TypeError): ElectrodeGrid(gshape, spacing, names={'1': 2}) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, names=('A', '1', 'A')) with pytest.raises(TypeError): ElectrodeGrid(gshape, spacing, names=(1, 'A')) with pytest.raises(TypeError): ElectrodeGrid(gshape, spacing, names=('A', 1)) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, names=('A', '~')) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, names=('~', 'A')) # Test all naming conventions: gshape = (2, 3) egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('A', '1')) # print([e for e in egrid.keys()]) npt.assert_equal([e for e in egrid.electrode_names], ['A1', 'A2', 'A3', 'B1', 'B2', 'B3']) egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('1', 'A')) # print([e for e in egrid.keys()]) # egrid = ElectrodeGrid(shape, names=('A', '1')) npt.assert_equal([e for e in egrid.electrode_names], ['A1', 'B1', 'C1', 'A2', 'B2', 'C2']) egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('1', '1')) # print([e for e in egrid.keys()]) npt.assert_equal([e for e in egrid.electrode_names], ['11', '12', '13', '21', '22', '23']) egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('A', 'A')) # print([e for e in egrid.keys()]) npt.assert_equal([e for e in egrid.electrode_names], ['AA', 'AB', 'AC', 'BA', 'BB', 'BC']) # Still starts at A: egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('B', '1')) npt.assert_equal([e for e in egrid.electrode_names], ['A1', 'A2', 'A3', 'B1', 'B2', 'B3']) egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('A', '2')) npt.assert_equal([e for e in egrid.electrode_names], ['A1', 'A2', 'A3', 'B1', 'B2', 'B3']) # Reversal: egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('-A', '1')) npt.assert_equal([e for e in egrid.electrode_names], ['B1', 'B2', 'B3', 'A1', 'A2', 'A3']) egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=('A', '-1')) npt.assert_equal([e for e in egrid.electrode_names], ['A3', 'A2', 'A1', 'B3', 'B2', 'B1']) # test unique names egrid = ElectrodeGrid(gshape, spacing, type=gtype, names=['53', '18', '00', '81', '11', '12']) npt.assert_equal([e for e in egrid.electrode_names], ['53', '18', '00', '81', '11', '12'])
def test_ElectrodeGrid(gtype): # Must pass in tuple/list of (rows, cols) for grid shape: with pytest.raises(TypeError): ElectrodeGrid("badinstantiation") with pytest.raises(TypeError): ElectrodeGrid(OrderedDict({'badinstantiation': 0})) with pytest.raises(ValueError): ElectrodeGrid([0], 10) with pytest.raises(ValueError): ElectrodeGrid([1, 2, 3], 10) with pytest.raises(TypeError): ElectrodeGrid({'1': 2}, 10) # Must pass in valid Electrode type: with pytest.raises(TypeError): ElectrodeGrid((2, 3), 10, type=gtype, etype=ElectrodeArray) with pytest.raises(TypeError): ElectrodeGrid((2, 3), 10, type=gtype, etype="foo") # Must pass in valid Orientation value: with pytest.raises(ValueError): ElectrodeGrid((2, 3), 10, type=gtype, orientation="foo") with pytest.raises(TypeError): ElectrodeGrid((2, 3), 10, type=gtype, orientation=False) # Must pass in radius `r` for grid of DiskElectrode objects: gshape = (4, 5) spacing = 100 grid = ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, r=13) for (_, e) in grid.electrodes.items(): npt.assert_almost_equal(e.r, 13) grid = ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, r=np.arange(1, np.prod(gshape) + 1)) for i, (_, e) in enumerate(grid.electrodes.items()): npt.assert_almost_equal(e.r, i + 1) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, radius=10) # Number of radii must match number of electrodes with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, radius=[2, 13, 14]) # Only DiskElectrode needs r, not PointSource: with pytest.raises(TypeError): ElectrodeGrid(gshape, spacing, type=gtype, r=10) # Must pass in radius `r` for grid of DiskElectrode objects: gshape = (4, 5) spacing = 100 with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, radius=10) # Number of radii must match number of electrodes with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type=gtype, etype=DiskElectrode, radius=[2, 13]) # Must pass in valid grid type: with pytest.raises(TypeError): ElectrodeGrid(gshape, spacing, type=DiskElectrode) with pytest.raises(ValueError): ElectrodeGrid(gshape, spacing, type='unknown') # Slots: npt.assert_equal(hasattr(grid, '__slots__'), True) npt.assert_equal(hasattr(grid, '__dict__'), False)