def generate_input_rates(module_field_width_dict, basis_function='gaussian', spacing_factor=1.0, peak_rate=1.): input_nodes_dict = {} input_groups_dict = {} input_rates_dict = {} for m in module_field_width_dict: nodes, groups, _ = poisson_disc_nodes(module_field_width_dict[m], (vert, smp)) input_groups_dict[m] = groups input_nodes_dict[m] = nodes input_rates_dict[m] = {} for i in range(nodes.shape[0]): xs = [[nodes[i, 0], nodes[i, 1]]] x_obs = np.asarray(xs).reshape((1, -1)) u_obs = np.asarray([[peak_rate]]).reshape((1, -1)) if basis_function == 'constant': input_rate_ip = lambda xx, yy: xx, yy else: input_rate_ip = Rbf(x_obs[:, 0], x_obs[:, 1], u_obs, function=basis_function, epsilon=module_field_width_dict[m] * spacing_factor) input_rates_dict[m][i] = input_rate_ip return input_nodes_dict, input_groups_dict, input_rates_dict
def generate_input_rates(spatial_domain, module_field_width_dict, basis_function='gaussian', spacing_factor=1.0, peak_rate=1.): input_nodes_dict = {} input_groups_dict = {} input_rates_dict = {} n_modules = len(module_field_width_dict) if isinstance(spacing_factor, float): spacing_factors = [spacing_factor] * n_modules else: spacing_factors = spacing_factor print(f"spacing factors: {spacing_factors}") if isinstance(peak_rate, float): peak_rates = [peak_rate] * n_modules else: peak_rates = peak_rate print(f"peak_rates: {peak_rates}") vert, smp = spatial_domain for m in sorted(module_field_width_dict): nodes, groups, _ = poisson_disc_nodes(module_field_width_dict[m], (vert, smp)) print( f"Generated {nodes.shape[0]} nodes for field width {module_field_width_dict[m]}" ) input_groups_dict[m] = groups input_nodes_dict[m] = nodes input_rates_dict[m] = {} for i in range(nodes.shape[0]): xs = [[nodes[i, 0], nodes[i, 1]]] x_obs = np.asarray(xs).reshape((1, -1)) u_obs = np.asarray([[peak_rates[m]]]).reshape((1, -1)) if basis_function == 'constant': input_rate_ip = lambda xx, yy: xx, yy else: input_rate_ip = Rbf(x_obs[:, 0], x_obs[:, 1], u_obs, function=basis_function, epsilon=module_field_width_dict[m] * spacing_factors[m]) input_rates_dict[m][i] = input_rate_ip return input_nodes_dict, input_groups_dict, input_rates_dict
# the hyperviscosity factor nu = 1e-6 # whether to plot the eigenvalues for the state differentiation matrix. All the # eigenvalues must have a negative real component for the time stepping to be # stable plot_eigs = False # number of nodes used for each RBF-FD stencil stencil_size = 50 # the polynomial order for generating the RBF-FD weights order = 4 # the RBF used for generating the RBF-FD weights phi = 'phs5' # generate the nodes nodes, groups, normals = poisson_disc_nodes( spacing, (vert, smp), boundary_groups={'all': range(len(smp))}, boundary_groups_with_ghosts=['all']) n = nodes.shape[0] # We will solve the wave equation by numerically integrating the state vector # `z`. The state vector is a concatenation of `u` and `v`. `u` is a (n,) array # consisting of: # # - the displacements at the interior at `u[groups['interior']]` # - the displacements at the boundary at `u[groups['boundary:all']]` # - the free boundary conditions at `u[groups['ghosts:all']]` # # `v` is a (n,) array and it is the time derivative of `u` # create a new node group for convenience groups['interior+boundary:all'] = np.hstack(
def generate_random_trajectory(arena, max_distance=None, spacing=10.0, temporal_resolution=1., velocity=30., equilibration_duration=None, local_random=None, n_trials=1): """ Construct coordinate arrays for a spatial trajectory, considering run velocity to interpolate at the specified temporal resolution. Optionally, the trajectory can be prepended with extra distance traveled for a specified network equilibration time, with the intention that the user discards spikes generated during this period before analysis. :param trajectory: namedtuple :param temporal_resolution: float (s) :param equilibration_duration: float (s) :return: tuple of array """ if local_random is None: local_random = np.random.RandomState(0) vert, smp = arena # generate the nodes. `nodes` is a (N, 2) float array, `groups` is a dict # identifying which group each node is in. nodes, groups, _ = poisson_disc_nodes(spacing, (vert, smp)) N = nodes.shape[0] tri = Delaunay(nodes) G = nx.Graph() for path in tri.simplices: nx.add_path(G, path) # Choose a starting point path_distance = 0. path_nodes = [] p = None s = local_random.choice(N) visited = deque(maxlen=5) while ((max_distance is None) or (path_distance < max_distance)): neighbors = list(G.neighbors(s)) visited.append(s) path_nodes.append(s) if p is not None: path_distance = path_distance + euclidean_distance( nodes[s], nodes[p]) p = s print(path_distance) candidates = [n for n in neighbors if n not in visited] if len(candidates) == 0: break else: selected = local_random.choice(len(candidates)) s = candidates[selected] input_trajectory = nodes[path_nodes] trajectory_lst = [] for i_trial in range(n_trials): trajectory_lst.append(input_trajectory) trajectory = np.concatenate(trajectory_lst) velocity = velocity # (cm / s) spatial_resolution = velocity * temporal_resolution x = trajectory[:, 0] y = trajectory[:, 1] if equilibration_duration is not None: equilibration_distance = velocity / equilibration_duration x = np.insert(x, 0, x[0] - equilibration_distance) y = np.insert(y, 0, y[0]) else: equilibration_duration = 0. equilibration_distance = 0. segment_lengths = np.sqrt((np.diff(x)**2. + np.diff(y)**2.)) distance = np.insert(np.cumsum(segment_lengths), 0, 0.) interp_distance = np.arange(distance.min(), distance.max() + spatial_resolution / 2., spatial_resolution) interp_x = np.interp(interp_distance, distance, x) interp_y = np.interp(interp_distance, distance, y) t = interp_distance / velocity # s t = np.subtract(t, equilibration_duration) interp_distance -= equilibration_distance return t, interp_x, interp_y, interp_distance
# size of RBF-FD stencils n = 30 # lame parameters lamb = 1.0 mu = 1.0 # z component of body for body_force = 1.0 ## Build and solve for displacements and strain ##################################################################### # generate nodes. The nodes are assigned groups based on which simplex # they lay on boundary_groups = {'fixed':[0], 'free':[1, 2, 3]} nodes, groups, normals = poisson_disc_nodes( dx, (vert, smp), boundary_groups=boundary_groups, boundary_groups_with_ghosts=['free']) # `nodes` : (N, 2) float array # `groups` : dictionary containing index sets. It has the keys # "interior", "boundary:free", "boundary:fixed", # "ghosts:free". # `normals : (N, 2) float array ## Create the sparse submatrices for the system matrix N = nodes.shape[0] G_xx = sp.coo_matrix((N, N)) G_xy = sp.coo_matrix((N, N)) G_yx = sp.coo_matrix((N, N)) G_yy = sp.coo_matrix((N, N)) ## Enforce the PDE on interior nodes AND the free surface nodes
from rbf.pde.geometry import contains from rbf.pde.nodes import poisson_disc_nodes import matplotlib.pyplot as plt # Define the problem domain with line segments. vert = np.array([[0.0, 0.0], [2.0, 0.0], [2.0, 1.0], [1.0, 1.0], [1.0, 2.0], [0.0, 2.0]]) smp = np.array([[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 0]]) spacing = 0.07 # approximate spacing between nodes eps = 0.3 / spacing # shape parameter # generate the nodes. `nodes` is a (N, 2) float array, `groups` is a dict # identifying which group each node is in nodes, groups, _ = poisson_disc_nodes(spacing, (vert, smp)) N = nodes.shape[0] # create "left hand side" matrix A = np.empty((N, N)) A[groups['interior']] = mq(nodes[groups['interior']], nodes, eps=eps, diff=[2, 0]) A[groups['interior']] += mq(nodes[groups['interior']], nodes, eps=eps, diff=[0, 2]) A[groups['boundary:all']] = mq(nodes[groups['boundary:all']], nodes, eps=eps) # create "right hand side" vector
simplices = np.array([[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11], [11, 12], [12, 13], [13, 14], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [19, 4]]) boundary_groups = { 'box': [0, 1, 2, 3], 'circle': [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] } # Generate the nodes. `groups` identifies which group each node belongs to. # `normals` contains the normal vectors corresponding to each node (nan if the # node is not on a boundary). We are giving the circle boundary nodes ghost # nodes to improve the accuracy of the free boundary constraint. nodes, groups, normals = poisson_disc_nodes( node_spacing, (vertices, simplices), boundary_groups=boundary_groups, boundary_groups_with_ghosts=['circle']) # Create the LHS and RHS enforcing that the Lapacian is -5 at the interior # nodes A_interior = weight_matrix(nodes[groups['interior']], nodes, stencil_size, [[2, 0], [0, 2]], phi=radial_basis_function, order=polynomial_order) b_interior = np.full(len(groups['interior']), -5.0) # Enforce that the solution is x at the box boundary nodes. A_boundary_box = weight_matrix(nodes[groups['boundary:box']], nodes,