Model of peripheral nerve with ephaptic coupling (Capllonch-Juan & Sepulveda 2020)

 Download zip file   Auto-launch 
Help downloading and running models
Accession:263988
We built a computational model of a peripheral nerve trunk in which the interstitial space between the fibers and the tissues is modelled using a resistor network, thus enabling distance-dependent ephaptic coupling between myelinated axons and between fascicles as well. We used the model to simulate a) the stimulation of a nerve trunk model with a cuff electrode, and b) the propagation of action potentials along the axons. Results were used to investigate the effect of ephaptic interactions on recruitment and selectivity stemming from artificial (i.e., neural implant) stimulation and on the relative timing between action potentials during propagation.
Reference:
1 . Capllonch-Juan M, Sepulveda F (2020) Modelling the effects of ephaptic coupling on selectivity and response patterns during artificial stimulation of peripheral nerves. PLoS Comput Biol 16:e1007826 [PubMed]
Citations  Citation Browser
Model Information (Click on a link to find other models with that property)
Model Type: Extracellular; Axon;
Brain Region(s)/Organism:
Cell Type(s): Myelinated neuron;
Channel(s):
Gap Junctions:
Receptor(s):
Gene(s):
Transmitter(s):
Simulation Environment: NEURON; Python;
Model Concept(s): Ephaptic coupling; Stimulus selectivity;
Implementer(s):
/
publication_data
dataset_04__eph_stim_vs_dist
fig9a
code
data
models
settings
src
x86_64
AXNODE.mod *
aaa_info_dataset
algebra.py *
analysis.py *
anatomy.py *
biophysics.py *
circlepacker.py *
contourhandler.py *
electrodes.py *
fill_nerve.py *
geometry.py *
get_extstim.py *
read_results.py *
sim_launcher.py *
simcontrol.py *
tessellations.py *
tools.py *
visualisation.py *
workspace.py *
                            
"""
This module administrates the contours
8 June 2018.
"""

import numpy as np
from collections import OrderedDict
import csv




def load_contours(name):
    """ Open a cotours csv file and read it """
    contours = OrderedDict()
    # Load the contours
    with open(name, "r") as f:
        fr = csv.reader(f)
        frl = list(fr)
        for line in frl:
            try:
                values = [float(item) for item in line]
            except ValueError:
                key = line[0]
                contours[key] = []
            else:
                contours[key].append(values)
    return contours

def read_poly(file_name):
    """
    Simple poly-file reader, that creates a python dictionary 
    with information about vertices, edges and holes.
    It assumes that vertices have no attributes or boundary markers.
    It assumes that edges have no boundary markers.
    No regional attributes or area constraints are parsed.
    Taken and adapted from: ...
    """

    output = {'vertices': None, 'holes': None, 'segments': None}
    
    # open file and store lines in a list
    file = open(file_name, 'r')
    lines = file.readlines()
    file.close()
    lines = [x.strip('\n').split() for x in lines]
    
    # Store vertices
    vertices= []
    N_vertices, dimension, attr, bdry_markers = [int(x) for x in lines[0]]
    # We assume attr = bdrt_markers = 0
    for k in range(N_vertices):
        label, x, y = [items for items in lines[k+1]]
        vertices.append([float(x), float(y)])
    output['vertices']=np.array(vertices)
    
    # Store segments
    segments = []
    N_segments, bdry_markers = [int(x) for x in lines[N_vertices+1]]
    for k in range(N_segments):
        label, pointer_1, pointer_2 = [items for items in lines[N_vertices+k+2]]
        segments.append([int(pointer_1)-1, int(pointer_2)-1])
    output['segments'] = np.array(segments)
    
    # Store holes
    N_holes = int(lines[N_segments+N_vertices+2][0])
    holes = []
    for k in range(N_holes):
        label, x, y = [items for items in lines[N_segments + N_vertices + 3 + k]]
        holes.append([float(x), float(y)])
    
    output['holes'] = np.array(holes)
    
    return output

def move_element(dic, key, newpos):
    """ Move the element with key 'key' of a dictionary 'dic' to the 
    position 'newpos' """
    newdic = OrderedDict()
    for i, (k, v) in enumerate(dic.items()):
        if k != key:
            newdic[k] = v
        if i == newpos:
            newdic[key] = dic[key]
    return newdic
    
def fill_random(c, n):
    """ Fill a contour given by the array c with a maximum of n random 
    points """

    # Contour's enclosing box
    left, right = c[:, 0].min(), c[:, 0].max()
    bottom, top = c[:, 1].min(), c[:, 1].max()

    # Dimensions
    width = right - left
    height = top - bottom

    # Generate random points in the box
    x = np.random.uniform(low=left, high=right, size=n)
    y = np.random.uniform(low=bottom, high=top, size=n)
    points = np.array([x, y]).T

    # 'Planar' polygon object for the contour
    polygon = pl.Polygon(c.tolist())

    # Check if the points are inside the polygon
    good_points = []
    for p in points:
        if polygon.contains_point(p):
            good_points.append(p)

    return polygon, np.array(good_points)

def remove_points(points):
    """ Remove points from 'points' that fall inside fascicles """
    survivors = []
    # Iterate over input points
    for p in points:
        discard = False
        # Iterate over fascicles
        for k, fp in polygons.items():
            if "Fascicle" in k:
                # Discard it and end this sub-loop if the point is inside the
                # fascicle's polygon
                if fp.contains_point(p):
                    discard = True
                    break
        # If it survived the loop, save it
        if not discard:
            survivors.append(p)

    return np.array(survivors)

def reduce_points(c, n):
    """ Reduce the number of points of contours 'c' by a factor of n in 
    order to reduce the computational burden. Only for contours with 
    more than n points """
    for k, a in c.items():
        if len(a) > n:
            c[k] = a[::n]
    return c

def c2pslg(c):
    """ Convert the contours of a nerve stored in the dictionary 'c' to a 
    dictionary describing a Planar Straight Line Graph (PSLG) """

    # newc = {'vertices': None, 'holes': None, 'segments': None}
    newc = {}
    # Total number of points
    nt = np.array([len(a) for a in c.values()]).sum()
    # Counter of processed points
    npr = 0
    # Generate the information
    vertices = []
    holes = []
    segments = []

    # Iterate over all the contours
    for k, a in c.items():
        n = len(a)
        i = 0
        # Append vertices and segments
        for (x, y) in a:
            vertices.append([x, y])
            # Only if there's more than one point here, add segments
            if n > 1:
                if i < n-1:
                    segments.append([npr+i, npr+i+1])
                    i += 1
                else:
                    segments.append([npr+i, npr])
        # Update npr
        npr += n

        # Holes
        if "Fascicle" in k:
            # Add the centroid (hand-maded for speed-up)
            a = np.array(a)
            holes.append([a[:, 0].mean(), a[:, 1].mean()])

    newc['vertices'] = np.array(vertices)
    # Condition: for there to be a 'holes' entry, there must be holes
    if len(holes) > 0:
        newc['holes'] = np.array(holes)
    newc['segments'] = np.array(segments)
    return newc