def locate_pads_on_nerve(self): """ Find the locations in the nerve corresponding to the pads """ # Iterate over the ring's pads self.contact_points = [] for i_pad in range(self.npads): # The pad's angular position determines which cable cell(s) # is (are) stimulated # Select which of the targets is in contact # with a pad 'i_pad' according to its angular position angdiff = np.abs(ws.contour_angles - self.thts[i_pad]) which_cables = np.where(angdiff == angdiff.min())[0] # Iterate over possible cables ncables_here = len(which_cables) for i_cable in which_cables: # For cable_cell i, see where this is try: i_sec, zpos = anatomy.locate(ws.seclens[i_cable], self.z) except TypeError: msg = 'ERROR: A ring of an electrode could not be placed on the nerve' ws.log(msg) ws.terminate() # Add the point point = {'cable': i_cable, 'section': i_sec, 'z': zpos} try: self.contact_points[i_pad].append(point) except IndexError: self.contact_points.append([point])
def __init__(self, name): self.name = name settings = ws.electrodes_settings[name] self.type = settings['type'] self.role = settings['role'] self.z = settings['z-position'] self.nrings = settings['number of rings'] self.rng_sp = settings['inter-ring distance'] self.nppr = settings['pads per ring'] self.length = settings['length'] self.thickness = settings['thickness'] self.rho = settings['insulator resistivity'] self.center = ws.nvt.circumcenter self.d_in = ws.nvt.circumdiameter self.d_out = self.d_in + 2. * self.thickness if self.role == 'stimulation': self.stimulation_protocol = \ settings['stimulation protocol'] # Necessary by-products # Ends of the cuff z = self.z l = self.length nrings = self.nrings left_end = z - 0.5 * l rght_end = z + 0.5 * l # Positions of the rings rings_halfspan = 0.5 * (nrings - 1) * self.rng_sp z_ring_left = z - rings_halfspan z_ring_rght = z + rings_halfspan self.rings_poss = np.linspace(z_ring_left, z_ring_rght, nrings) # Angular positions of the pads on the rings self.thts = settings['angular positions'] # Consistency check if len(self.thts) != self.nppr: msg = 'ERROR: Different number of pads and angles for them' ws.log(msg) ws.terminate() # Warning if size mismatch if z_ring_left < left_end or z_ring_rght > rght_end: msg = 'ERROR: Cuff electrode rings outside the cuff.' ws.log(msg) ws.terminate() # Store variables into attributes self.left_end = left_end self.rght_end = rght_end self.z_ring_left = z_ring_left self.z_ring_rght = z_ring_rght # Create rings self.create_rings()
def parameter_regressions(filename): """ Open and read a file with parameters over which to make regressions and obtain new expressions and values """ # Read data with open(filename, 'r') as f: frl = list(csv.reader(f)) keys = frl[0] data = np.array(frl[1:], dtype=np.float64) n_fields = len(keys) n_entries = len(data) data_dict = OrderedDict() for i in range(n_fields): data_dict[keys[i]] = data[:, i] # Independent variable indepvar = keys[0] # Dictionary containing the regressions regressions = OrderedDict() # Of course, indicate which one is the independent variable regressions['independent variable'] = indepvar for i, (k, v) in enumerate(list(data_dict.items())[1:]): x = data_dict[indepvar] # Linear regression slope, intercept, r_value, p_value, std_err = linregress(x, v) # Check if it's valid if intercept < 0: # Negative values, unacceptable. Use a polynomial fit # Quadratic fit parabolic_coeffs = np.polyfit(x, v, 2) if parabolic_coeffs[-1] < 0: # Not even a quadratic fit worked msg = 'ERROR: Could not obtain positive values for ' + k + ' for small ' + indepvar ws.log(msg) ws.terminate() # Give it a x-array that covers the whole domain x_ = np.linspace(0, x.max(), 100) ypol = polynomial(x_, parabolic_coeffs) # return polynomial regression a, b, c = parabolic_coeffs regressions[k] = lambda x: a * x**2 + b * x + c else: # Plot linear regression # Create straight line object and draw it sl = geo.StraightLine((0, intercept), slope) regressions[k] = sl.equation return regressions
def list_to_number(l): """ Given a list or a list of lists with ONLY ONE NUMBER INSIDE, retrieve that number. If there's more than one number, yield an error and quit """ # Check if it's a list or a number try: ll = len(l) except TypeError: # It's probably a number, so just return it as it is return float(l) l = np.array(l).flatten() if len(l) != 1: msg = 'ERROR: tools.list_to_number got a list with more than one number' ws.log(msg) ws.terminate() return float(l[0])
def __init__(self, name, index=0): PointElectrode.__init__(self, name, 0) settings = self.settings try: self.z = settings['z-position'] except KeyError: self.axon = settings['axon'] try: self.node = settings['node of Ranvier'] except KeyError: self.node = settings['internode'] self.position = settings['position'] else: # For a node of Ranvier, inject current in the middle self.position = 0.5 else: # Warning if position mismatch if self.z < 0. or self.z > ws.length: ws.log('ERROR: Electrode is outside the limits of the nerve.') ws.terminate() # Note: the warnings or errors for targetting a non-existing # node will be automatically raised by NEURON # Setting up this point is necessary to set up stimulation and # recording # Besides, it gives the process uniformity across # different types of electrodes cable_i = ws.nNAELC + self.axon k = 0 if "node of Ranvier" in settings.keys(): for j, sec in enumerate(ws.sections[cable_i]): secname = sec.name() if "NODE" in secname or "node" in secname: if k == self.node: break k += 1 self.point = {'cable': cable_i, 'section': j, 'z': self.position} self.set_stim_info()
def __new__(cls, verts, *args, **kwargs): lv = len(verts) # Validation if lv == 0: msg = 'ERROR: Point list or array is empty.' try: ws.log(msg) except AttributeError: print(msg) else: ws.terminate() elif lv == 1: msg = 'WARNING: Defined polygon with only 1 point:\n%s. Returing point' % str( verts) try: ws.log(msg) except AttributeError: print(msg) return Point(*verts[0]) elif lv == 2: msg = 'WARNING: Defined polygon with only 2 points:\n%s. Returing Segment' % str( verts) try: ws.log(msg) except AttributeError: print(msg) return Segment(verts) # elif lv == 3: # This is a triangle # return super(Triangle, cls).__new__(cls) # return super(Triangle, cls).__new__(cls) # I didn't get this to work... pass elif lv >= 3: # Now, this is a proper polygon. So, proceed. return super(Polygon, cls).__new__(cls)
def sanity_checks(): """ Perform some checks to make sure that everything is defined correctly and do whatever is necessary if not """ # Using the Resistor Network model implies... if ws.settings["nerve model"] == "resistor network": # that there is ephaptic coupling if not ws.EC["presence"]: msg = "WARNING: Using the Resistor Network Model implies "\ + "the presence of ephaptic coupling\nEphaptic "\ + "coupling was activated" ws.log(msg) ws.EC["presence"] = True ws.EC["use"] = "resistor network" # that the stimulation forcing can't be "pre-computed" if ws.settings["stimulation"]["method"] == "pre-computed": msg = "ERROR: Using the Resistor Network Model implies "\ + "that the stimulation method can't be pre-computed\n"\ + "Please check your settings" ws.log(msg) ws.terminate()