def test_deprecated(): assert_warns_msg(DeprecationWarning, MockClass1, 'Use ``qwerty`` instead') assert_warns_msg(DeprecationWarning, MockClass2().mymethod, 'since version 0.1, and will be removed in version 0.2') assert_warns_msg(DeprecationWarning, MockClass3, 'deprecated') assert_warns_msg(DeprecationWarning, mock_function, 'since version 0.4')
def test_Stimulus__stim(): stim = Stimulus(3) # User could try and motify the data container after the constructor, which # would lead to inconsistencies between data, electrodes, time. The new # property setting mechanism prevents that. # Requires dict: with pytest.raises(AttributeError): stim._stim = np.array([0, 1]) # Dict must have all required fields: fields = ['data', 'electrodes', 'time'] for field in fields: _fields = deepcopy(fields) _fields.remove(field) with pytest.raises(AttributeError): stim._stim = {f: None for f in _fields} # Data must be a 2-D NumPy array: data = {f: None for f in fields} with pytest.raises(ValueError): data['data'] = np.ones(3) stim._stim = data # Data rows must match electrodes: with pytest.raises(ValueError): data['data'] = np.ones((3, 4)) data['time'] = np.arange(4) data['electrodes'] = np.arange(2) stim._stim = data # Data columns must match time: with pytest.raises(ValueError): data['data'] = np.ones((3, 4)) data['electrodes'] = np.arange(3) data['time'] = np.arange(7) stim._stim = data # Time points must be unique: assert_warns_msg(UserWarning, _unique_timepoints, None, stim, data) # But if you do all the things right, you can reset the stimulus by hand: data['data'] = np.ones((3, 1)) data['electrodes'] = np.arange(3) data['time'] = None stim._stim = data data['data'] = np.ones((3, 1)) data['electrodes'] = np.arange(3) data['time'] = np.arange(1) stim._stim = data data['data'] = np.ones((3, 4)) data['electrodes'] = np.arange(3) data['time'] = np.array([0, 1, 1 + DT, 2]) stim._stim = data
def test_ScoreboardModel_predict_percept(): model = ScoreboardModel(xystep=0.55, rho=100, thresh_percept=0, xrange=(-20, 20), yrange=(-15, 15)) model.build() # Single-electrode stim: img_stim = np.zeros(60) img_stim[47] = 1 percept = model.predict_percept(ArgusII(stim=img_stim)) # Single bright pixel, very small Gaussian kernel: npt.assert_equal(np.sum(percept.data > 0.8), 1) npt.assert_equal(np.sum(percept.data > 0.5), 2) npt.assert_equal(np.sum(percept.data > 0.1), 7) npt.assert_equal(np.sum(percept.data > 0.00001), 32) # Brightest pixel is in lower right: npt.assert_almost_equal(percept.data[33, 46, 0], np.max(percept.data)) # Full Argus II: 60 bright spots model = ScoreboardModel(engine='serial', xystep=0.55, rho=100) model.build() percept = model.predict_percept(ArgusII(stim=np.ones(60))) npt.assert_equal(np.sum(np.isclose(percept.data, 0.8, rtol=0.1, atol=0.1)), 88) # Model gives same outcome as Spatial: spatial = ScoreboardSpatial(engine='serial', xystep=1, rho=100) spatial.build() spatial_percept = model.predict_percept(ArgusII(stim=np.ones(60))) npt.assert_almost_equal(percept.data, spatial_percept.data) npt.assert_equal(percept.time, None) # Warning for nonzero electrode-retina distances implant = ArgusI(stim=np.ones(16), z=10) msg = ("Nonzero electrode-retina distances do not have any effect on the " "model output.") assert_warns_msg(UserWarning, model.predict_percept, msg, implant)
def test_assert_warns_msg(): for warning in [UserWarning, DeprecationWarning]: assert_warns_msg(warning, _mock_warns, str(warning), category=warning)
def test_Stimulus(): # Slots: npt.assert_equal(hasattr(Stimulus(1), '__slots__'), True) npt.assert_equal(hasattr(Stimulus(1), '__dict__'), False) # One electrode: stim = Stimulus(3) npt.assert_equal(stim.shape, (1, 1)) npt.assert_equal(stim.electrodes, [0]) npt.assert_equal(stim.time, None) # One electrode with a name: stim = Stimulus(3, electrodes='AA001') npt.assert_equal(stim.shape, (1, 1)) npt.assert_equal(stim.electrodes, ['AA001']) npt.assert_equal(stim.time, None) # Ten electrodes, one will be trimmed: stim = Stimulus(np.arange(10), compress=True) npt.assert_equal(stim.shape, (9, 1)) npt.assert_equal(stim.electrodes, np.arange(1, 10)) npt.assert_equal(stim.time, None) # Electrodes + specific time, time will be trimmed: stim = Stimulus(np.ones((4, 3)), time=[-3, -2, -1], compress=True) npt.assert_equal(stim.shape, (4, 2)) npt.assert_equal(stim.time, [-3, -1]) # Electrodes + specific time, but don't trim: stim = Stimulus(np.ones((4, 3)), time=[-3, -2, -1], compress=False) npt.assert_equal(stim.shape, (4, 3)) npt.assert_equal(stim.time, [-3, -2, -1]) # Specific names: stim = Stimulus({'A1': 3, 'C5': 8}) npt.assert_equal(stim.shape, (2, 1)) npt.assert_equal(np.sort(stim.electrodes), np.sort(['A1', 'C5'])) npt.assert_equal(stim.time, None) # Specific names, renamed: stim = Stimulus({'A1': 3, 'C5': 8}, electrodes=['B7', 'B8']) npt.assert_equal(stim.shape, (2, 1)) npt.assert_equal(np.sort(stim.electrodes), np.sort(['B7', 'B8'])) npt.assert_equal(stim.time, None) # Electrodes x time, time will be trimmed: stim = Stimulus(np.ones((6, 100)), compress=True) npt.assert_equal(stim.shape, (6, 2)) # Single electrode in time: stim = Stimulus([[1, 5, 7, 2, 4]]) npt.assert_equal(stim.electrodes, [0]) npt.assert_equal(stim.shape, (1, 5)) # Specific electrode in time: stim = Stimulus({'C3': [[1, 4, 4, 3, 6]]}) npt.assert_equal(stim.electrodes, ['C3']) npt.assert_equal(stim.shape, (1, 5)) # Multiple specific electrodes in time: stim = Stimulus({'C3': [[0, 1, 2, 3]], 'F4': [[4, -1, 4, -1]]}) # Stimulus from a Stimulus (might happen in ProsthesisSystem): stim = Stimulus(Stimulus(4), electrodes='B3') npt.assert_equal(stim.shape, (1, 1)) npt.assert_equal(stim.electrodes, ['B3']) npt.assert_equal(stim.time, None) # Saves metadata: metadata = {'a': 0, 'b': 1} stim = Stimulus(3, metadata=metadata) npt.assert_equal(stim.metadata['user'], metadata) # List of lists instead of 2D NumPy array: stim = Stimulus([[1, 1, 1, 1, 1], [1, 1, 1, 1, 1]], compress=True) npt.assert_equal(stim.shape, (2, 2)) npt.assert_equal(stim.electrodes, [0, 1]) npt.assert_equal(stim.time, [0, 4]) # Tuple of tuples instead of 2D NumPy array: stim = Stimulus(((1, 1, 1, 1, 1), (1, 1, 1, 1, 1)), compress=True) npt.assert_equal(stim.shape, (2, 2)) npt.assert_equal(stim.electrodes, [0, 1]) npt.assert_equal(stim.time, [0, 4]) # Zero activation: source = np.zeros((2, 4)) stim = Stimulus(source, compress=True) npt.assert_equal(stim.shape, (0, 2)) npt.assert_equal(stim.time, [0, source.shape[1] - 1]) stim = Stimulus(source, compress=False) npt.assert_equal(stim.shape, source.shape) npt.assert_equal(stim.time, np.arange(source.shape[1])) # Annoying but possible: stim = Stimulus([]) npt.assert_equal(stim.time, None) npt.assert_equal(len(stim.data), 0) npt.assert_equal(len(stim.electrodes), 0) npt.assert_equal(stim.shape, (0, )) # Rename electrodes: stim = Stimulus(np.ones((2, 5)), compress=True) npt.assert_equal(stim.electrodes, [0, 1]) stim = Stimulus(stim, electrodes=['A3', 'B8']) npt.assert_equal(stim.electrodes, ['A3', 'B8']) npt.assert_equal(stim.time, [0, 4]) # Individual stimuli might already have electrode names: stim = Stimulus([Stimulus(1, electrodes='B1')]) npt.assert_equal(stim.electrodes, ['B1']) # Duplicate names will be fixed (with a warning message): stim = Stimulus([Stimulus(1), Stimulus(2)]) npt.assert_equal(stim.electrodes, [0, 1]) # When passing a dict and the stimuli already have electrode names, the # keys of the dict prevail: stim = Stimulus({'A1': Stimulus(1, electrodes='B2')}) npt.assert_equal(stim.electrodes, ['A1']) # Specify new time points: stim = Stimulus(np.ones((2, 5)), compress=True) npt.assert_equal(stim.time, [0, 4]) stim = Stimulus(stim, time=np.array(stim.time) / 10.0) npt.assert_equal(stim.electrodes, [0, 1]) npt.assert_almost_equal(stim.time, [0, 0.4]) # Charge-balanced: npt.assert_equal(Stimulus(0).is_charge_balanced, True) npt.assert_equal(Stimulus(1).is_charge_balanced, False) npt.assert_equal(Stimulus([0, 0]).is_charge_balanced, True) npt.assert_equal(Stimulus([[0, 0]]).is_charge_balanced, True) npt.assert_equal(Stimulus([1, -1]).is_charge_balanced, False) npt.assert_equal(Stimulus([[1, -1]]).is_charge_balanced, True) npt.assert_equal(Stimulus([[1, -1], [0, 0.5]]).is_charge_balanced, False) # Not allowed: with pytest.raises(ValueError): # First one doesn't have time: stim = Stimulus({'A2': 1, 'C3': [[1, 2, 3]]}) with pytest.raises(ValueError): # Invalid source type: stim = Stimulus(np.ones((3, 4, 5, 6))) with pytest.raises(TypeError): # Invalid source type: stim = Stimulus("invalid") with pytest.raises(ValueError): # Wrong number of electrodes: stim = Stimulus([3, 4], electrodes='A1') with pytest.raises(ValueError): # Wrong number of time points: stim = Stimulus(np.ones((3, 5)), time=[0, 1, 2]) with pytest.raises(ValueError): # Can't force time: stim = Stimulus(3, time=[0.4]) assert_warns_msg(UserWarning, Stimulus, None, [[1, 2, 3]], time=[1, 2, 1.9])
def test_AxonMapModel_predict_percept(engine): model = AxonMapModel(xystep=0.55, axlambda=100, rho=100, thresh_percept=0, engine=engine, xrange=(-20, 20), yrange=(-15, 15), n_axons=500) model.build() # Single-electrode stim: img_stim = np.zeros(60) img_stim[47] = 1 # Axon map jax predict_percept not implemented yet if engine == 'jax': with pytest.raises(NotImplementedError): percept = model.predict_percept(ArgusII(stim=img_stim)) return percept = model.predict_percept(ArgusII(stim=img_stim)) # Single bright pixel, rest of arc is less bright: npt.assert_equal(np.sum(percept.data > 0.8), 1) npt.assert_equal(np.sum(percept.data > 0.6), 2) npt.assert_equal(np.sum(percept.data > 0.1), 7) npt.assert_equal(np.sum(percept.data > 0.0001), 31) # Overall only a few bright pixels: npt.assert_almost_equal(np.sum(percept.data), 3.3087, decimal=3) # Brightest pixel is in lower right: npt.assert_almost_equal(percept.data[33, 46, 0], np.max(percept.data)) # Top half is empty: npt.assert_almost_equal(np.sum(percept.data[:27, :, 0]), 0) # Same for lower band: npt.assert_almost_equal(np.sum(percept.data[39:, :, 0]), 0) # Full Argus II with small lambda: 60 bright spots model = AxonMapModel(engine='serial', xystep=1, rho=100, axlambda=40, xrange=(-20, 20), yrange=(-15, 15), n_axons=500) model.build() percept = model.predict_percept(ArgusII(stim=np.ones(60))) # Most spots are pretty bright, but there are 2 dimmer ones (due to their # location on the retina): npt.assert_equal(np.sum(percept.data > 0.5), 28) npt.assert_equal(np.sum(percept.data > 0.275), 56) # Model gives same outcome as Spatial: spatial = AxonMapSpatial(engine='serial', xystep=1, rho=100, axlambda=40, xrange=(-20, 20), yrange=(-15, 15), n_axons=500) spatial.build() spatial_percept = spatial.predict_percept(ArgusII(stim=np.ones(60))) npt.assert_almost_equal(percept.data, spatial_percept.data) npt.assert_equal(percept.time, None) # Warning for nonzero electrode-retina distances implant = ArgusI(stim=np.ones(16), z=10) msg = ("Nonzero electrode-retina distances do not have any effect on the " "model output.") assert_warns_msg(UserWarning, model.predict_percept, msg, implant)