Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
# Potential on the electrode surface (Eq. 9 in Wiley & Webster):
if radial_dist > self.r:
# Outside the electrode:
return 2.0 * v0 / np.pi * np.arcsin(self.r / radial_dist)
else:
# On the electrode:
return v0
else:
# Off the electrode surface (Eq. 10):
numer = 2 * self.r
denom = np.sqrt((radial_dist - self.r) ** 2 + axial_dist ** 2)
denom += np.sqrt((radial_dist + self.r) ** 2 + axial_dist ** 2)
return 2.0 * v0 / np.pi * np.arcsin(numer / denom)
class SquareElectrode(Electrode):
"""Square electrode
.. versionadded:: 0.7
Parameters
----------
x/y/z : double
3D location that is the center of the square electrode
a : double
Side length of the square
"""
# Frozen class: User cannot add more class attributes
__slots__ = ('a')
def __init__(self, x, y, z, a):
raise TypeError("'shape' must be a tuple/list of (rows, cols)")
if len(shape) != 2:
raise ValueError("'shape' must have two elements: (rows, cols)")
if np.prod(shape) <= 0:
raise ValueError("Grid must have all non-zero rows and columns.")
if not isinstance(type, str):
raise TypeError("'type' must be a string, either 'rect' or 'hex'.")
if not isinstance(orientation, str):
raise TypeError("'orientation' must be a string, either "
"'horizontal' or 'veritical'.")
if type not in ['rect', 'hex']:
raise ValueError("'type' must be either 'rect' or 'hex'.")
if orientation not in ['horizontal', 'vertical']:
raise ValueError(
"'orientation' must be either 'horizontal' or 'vertical'.")
if not issubclass(etype, Electrode):
raise TypeError("'etype' must be a valid Electrode object.")
if issubclass(etype, DiskElectrode):
if 'r' not in kwargs.keys():
raise ValueError("A DiskElectrode needs a radius ``r``.")
if not isinstance(names, (tuple, list, np.ndarray)):
raise TypeError("'names' must be a tuple or list, not "
"%s." % type(names))
else:
if len(names) != 2 and len(names) != np.prod(shape):
raise ValueError("'names' must either have two entries for "
"rows/columns or %d entries, not "
"%d" % (np.prod(shape), len(names)))
self.shape = shape
self.type = type
self.spacing = spacing
# Special case: draw multiple objects
for p, kw in zip(self.plot_patch, self.plot_kwargs):
ax.add_patch(p((self.x, self.y), zorder=10, **kw))
else:
# Regular use case: single object
ax.add_patch(self.plot_patch((self.x, self.y), zorder=10,
**self.plot_kwargs))
# This is needed in MPL 3.0.X to set the axis limit correctly:
ax.autoscale_view()
if autoscale:
ax.set_xlim(self.x - pad, self.x + pad)
ax.set_ylim(self.y - pad, self.y + pad)
return ax
class PointSource(Electrode):
"""Idealized current point source
Parameters
----------
x/y/z : double
3D location of the point source
"""
# Frozen class: User cannot add more class attributes
__slots__ = ()
def __init__(self, x, y, z):
super(PointSource, self).__init__(x, y, z)
self.plot_patch = Circle
self.plot_kwargs = {'radius': 5, 'linewidth': 2,
'ec': (0.3, 0.3, 0.3, 1),
V(r) = \\frac{\\sigma I}{4 \\pi r},
where :math:`\\sigma` is the resistivity of the extracellular solution
(typically Ames medium, :math:`\\sigma = 110 \\Ohm cm`),
:math:`I` is the amplitude of the constant current pulse,
and :math:`r` is the distance from the stimulating electrode to the
point at which the voltage is being computed.
"""
r = np.sqrt((x - self.x) ** 2 + (y - self.y) ** 2 + (z - self.z) ** 2)
if np.isclose(r, 0):
return sigma * amp
return sigma * amp / (4.0 * np.pi * r)
class DiskElectrode(Electrode):
"""Circular disk electrode
Parameters
----------
x/y/z : double
3D location that is the center of the disk electrode
r : double
Disk radius in the x,y plane
"""
# Frozen class: User cannot add more class attributes
__slots__ = ('r',)
def __init__(self, x, y, z, r):
super(DiskElectrode, self).__init__(x, y, z)
if isinstance(r, (Sequence, np.ndarray)):
def add_electrode(self, name, electrode):
"""Add an electrode to the array
Parameters
----------
name : int|str|...
Electrode name or index
electrode : implants.Electrode
An Electrode object, such as a PointSource or a DiskElectrode.
"""
if not isinstance(electrode, Electrode):
raise TypeError(("Electrode %s must be an Electrode object, not "
"%s.") % (name, type(electrode)))
if name in self.electrodes.keys():
raise ValueError(("Cannot add electrode: key '%s' already "
"exists.") % name)
self._electrodes.update({name: electrode})
def earray(self, earray):
"""Electrode array setter (called upon ``self.earray = earray``)"""
# Assign the electrode array:
if isinstance(earray, Electrode):
# For convenience, build an array from a single electrode:
earray = ElectrodeArray(earray)
if not isinstance(earray, ElectrodeArray):
raise TypeError("'earray' must be an ElectrodeArray object, not "
"%s." % type(earray))
self._earray = earray
self.plot_patch = Rectangle
self.plot_kwargs = {'width': a, 'height': a, 'angle': 0,
'linewidth': 2, 'ec': (0.3, 0.3, 0.3, 1),
'fc': (0.8, 0.8, 0.8, 0.7)}
def _pprint_params(self):
"""Return dict of class attributes to pretty-print"""
params = super()._pprint_params()
params.update({'a': self.a})
return params
def electric_potential(self, x, y, z, v0):
raise NotImplementedError
class HexElectrode(Electrode):
"""Hexagonal electrode
.. versionadded:: 0.7
Parameters
----------
x/y/z : double
3D location that is the center of the hexagonal electrode
a : double
Length of line drawn from the center of the hexagon to the midpoint of
one of its sides.
"""
# Frozen class: User cannot add more class attributes
__slots__ = ('a')