def render_all(): G, dG = gds.square_lattice(14, 28, with_boundaries=True) v1, p1 = poiseuille(G, dG) G, dG = gds.triangular_lattice(14, 58, with_boundaries=True) v2, p2 = poiseuille(G, dG) G, dG = gds.hexagonal_lattice(14, 29, with_boundaries=True) v3, p3 = poiseuille(G, dG) G, dG = gds.voronoi_lattice(10, 100, with_boundaries=True, eps=0.07) v4, p4 = poiseuille(G, dG) sys = gds.couple({ 'velocity (sq)': v1, 'velocity (tri)': v2, 'velocity (hex)': v3, 'velocity (voronoi)': v4, 'pressure (sq)': p1, 'pressure (tri)': p2, 'pressure (hex)': p3, 'pressure (voronoi)': p4, 'vorticity (sq)': v1.project(gds.GraphDomain.faces, lambda v: v.curl()), 'vorticity (tri)': v2.project(gds.GraphDomain.faces, lambda v: v.curl()), 'vorticity (hex)': v3.project(gds.GraphDomain.faces, lambda v: v.curl()), 'vorticity (voronoi)': v4.project(gds.GraphDomain.faces, lambda v: v.curl()), }) gds.render(sys, canvas=gds.grid_canvas(sys.observables.values(), 4), edge_max=0.6, dynamic_ranges=True, plot_width=900, node_size=0.04)
def von_karman_projected(): m = 20 n = 40 gradP = 100.0 inlet_v = 5.0 outlet_p = 0.0 G, (l, r, t, b) = gds.triangular_lattice(m, n, with_boundaries=True) # G, (l, r, t, b) = gds.square_lattice(m, n, with_boundaries=True) # G, (l, r, t, b) = gds.hexagonal_lattice(m, n, with_boundaries=True) # G = gds.triangular_cylinder(m, n) # G = gds.square_cylinder(m, n) # l, r = G.l_boundary, G.r_boundary j, k = 3, m // 2 # Introduce occlusion obstacle = [ (j, k), # (j+1, k), # (j+1, k+1), # (j+1, k-1), # (j-1, k+1), # (j, k+2), ] G.remove_nodes_from(obstacle) velocity, pressure = fluid_projected.navier_stokes(G, viscosity=0.0001) pressure.set_constraints(dirichlet=gds.combine_bcs( {n: gradP / 2 for n in l.nodes}, {n: -gradP / 2 for n in r.nodes})) # velocity.set_constraints(dirichlet=gds.combine_bcs( # {((0, i), (1, i)): inlet_v for i in range(1, m)}, # {((n//2, i), (n//2+1, i)): inlet_v for i in range(1, m)}, # {((n//2-1, 2*i+1), (n//2, 2*i+1)): inlet_v for i in range(0, m//2)}, # # gds.utils.bidict({e: 0 for e in obstacle_boundary}), # gds.utils.bidict({e: 0 for e in t.edges}), # gds.utils.bidict({e: 0 for e in b.edges}) # )) sys = gds.couple({ 'velocity': velocity, # 'divergence': velocity.project(gds.GraphDomain.nodes, lambda v: v.div()), 'vorticity': velocity.project(gds.GraphDomain.faces, lambda v: v.curl()), 'pressure': pressure, # 'tracer': lagrangian_tracer(velocity), # 'advective': velocity.project(gds.GraphDomain.edges, lambda v: -advector(v)), # 'L2': velocity.project(PointObservable, lambda v: np.sqrt(np.dot(v.y, v.y))), # 'dK/dt': velocity.project(PointObservable, lambda v: np.dot(v.y, v.leray_project(-advector(v)))), }) gds.render(sys, canvas=gds.grid_canvas(sys.observables.values(), 3), edge_max=0.6, dynamic_ranges=True, edge_colors=True, edge_palette=cc.bgy)
def show_L1_eigfuns(G, n=np.inf, **kwargs): ''' Show eigenfunctions of 0-Laplacian ''' obs = gds.edge_gds(G) # L = np.array(nx.laplacian_matrix(G).todense()) L = -obs.laplacian(np.eye(obs.ndim)) # vals, vecs = sp.sparse.linalg.eigs(-L, k=n, which='SM') vals, vecs = np.linalg.eigh(L) vals, vecs = np.real(vals), np.real(vecs) vals = np.round(vals, 6) # pdb.set_trace() sys = dict() sys['Surface'] = gds.face_gds(G) sys['Surface'].set_evolution(nil=True) canvas = dict() canvas['Surface'] = [[[sys['Surface']]]] for i, (ev, vec) in enumerate(sorted(zip(vals, vecs.T), key=lambda x: np.abs(x[0]))): obs = gds.edge_gds(G) obs.set_evolution(nil=True) obs.set_initial(y0=lambda x: vec[obs.X[x]]) if ev in canvas: sys[f'eigval_{ev} eigfun_{len(canvas[ev])}'] = obs canvas[ev].append([[obs]]) else: sys[f'eigval_{ev} eigfun_{0}'] = obs canvas[ev] = [[[obs]]] if i == n: break # canvas = sorted(list(canvas.values()), key=len) canvas = list(canvas.values()) sys = gds.couple(sys) gds.render(sys, canvas=canvas, n_spring_iters=1200, title=f'L1-eigenfunctions', **kwargs)
def render(): p1, v1 = sq_couette_ivp() # p1, v1 = tri_couette_ivp() # p1, v1 = hex_couette_ivp() # p1, v1 = sq_couette() # p2, v2 = tri_couette() # p3, v3 = hex_couette() sys = gds.couple({ 'velocity': v1, # 'velocity_tri': v2, # 'velocity_hex': v3, 'pressure': p1, # 'pressure_tri': p2, # 'pressure_hex': p3, 'vorticity': v1.project(gds.GraphDomain.faces, lambda v: v.curl()), # 'vorticity_tri': v2.project(gds.GraphDomain.faces, lambda v: v.curl()), # 'vorticity_hex': v3.project(gds.GraphDomain.faces, lambda v: v.curl()), # 'divergence_square': v1.project(gds.GraphDomain.nodes, lambda v: v.div()), 'kinetic energy': v1.project(PointObservable, lambda v: (v1.y ** 2).sum(), min_rng=0.1), 'momentum': v1.project(PointObservable, lambda v: np.abs(v1.y).sum(), min_rng=0.1), 'rotational energy': v1.project(PointObservable, lambda v: (v1.curl() ** 2).sum(), min_rng=0.1), 'angular momentum': v1.project(PointObservable, lambda v: np.abs(v1.curl()).sum(), min_rng=0.1), }) gds.render(sys, canvas=gds.grid_canvas(sys.observables.values(), 3), edge_max=0.6, dynamic_ranges=True, min_rng_size=1e-2)
def dump(): p1, v1 = sq_couette() p2, v2 = tri_couette() p3, v3 = hex_couette() sys = gds.couple({ 'velocity_square': v1, 'velocity_tri': v2, 'velocity_hex': v3, 'pressure_square': p1, 'pressure_tri': p2, 'pressure_hex': p3, 'vorticity_square': v1.project(gds.GraphDomain.faces, lambda v: v.curl()), 'vorticity_tri': v2.project(gds.GraphDomain.faces, lambda v: v.curl()), 'vorticity_hex': v3.project(gds.GraphDomain.faces, lambda v: v.curl()), 'diffusion_square': v1.project(gds.GraphDomain.edges, lambda v: v.laplacian()), 'diffusion_tri': v2.project(gds.GraphDomain.edges, lambda v: v.laplacian()), 'diffusion_hex': v3.project(gds.GraphDomain.edges, lambda v: v.laplacian()), 'advection_square': v1.project(gds.GraphDomain.edges, lambda v: -v.advect()), 'advection_tri': v2.project(gds.GraphDomain.edges, lambda v: -v.advect()), 'advection_hex': v3.project(gds.GraphDomain.edges, lambda v: -v.advect()), 'divergence_square': v1.project(gds.GraphDomain.nodes, lambda v: v.div()), 'divergence_tri': v2.project(gds.GraphDomain.nodes, lambda v: v.div()), 'divergence_hex': v3.project(gds.GraphDomain.nodes, lambda v: v.div()), }) sys.solve_to_disk(2.0, 0.01, 'couette')
def test_curl(): G1 = nx.Graph() G1.add_nodes_from([1, 2, 3, 4]) G1.add_edges_from([(1, 2), (2, 3), (3, 4), (4, 1)]) v1 = gds.edge_gds(G1) v1.set_evolution(nil=True) v1.set_initial(y0=lambda e: 1 if e == (1, 2) else 0) G2 = nx.Graph() G2.add_nodes_from([1, 2, 3, 4, 5, 6]) G2.add_edges_from([(1, 2), (2, 3), (3, 4), (4, 1), (1, 5), (5, 6), (6, 2)]) v2 = gds.edge_gds(G2) v2.set_evolution(nil=True) v2.set_initial(y0=lambda e: 1 if e == (1, 2) else 0) sys = gds.couple({ 'velocity1': v1, 'curl1': v1.project(gds.GraphDomain.faces, lambda v: v.curl()), 'curl*curl1': v1.project(gds.GraphDomain.edges, lambda v: v.curl_face.T @ v.curl_face @ v.y), 'velocity2': v2, 'curl2': v2.project(gds.GraphDomain.faces, lambda v: v.curl()), 'curl*curl2': v2.project(gds.GraphDomain.edges, lambda v: v.curl_face.T @ v.curl_face @ v.y) }) gds.render(sys, edge_max=0.5, canvas=gds.grid_canvas(sys.observables.values(), 3), dynamic_ranges=True)
def show_harmonics(G, k=0, n=np.inf, **kwargs): ''' Show harmonics of Hodge k-Laplacian ''' def make_observable(): # TODO: use the simplicial decomposition here return { 0: gds.node_gds, 1: gds.edge_gds, 2: gds.face_gds, }[k](G) obs = make_observable() L = -obs.laplacian(np.eye(obs.ndim)) print('Laplacian rank: ', np.linalg.matrix_rank(L)) null = sp.linalg.null_space(L).T sys = dict() sys['Surface'] = gds.face_gds(G) sys['Surface'].set_evolution(nil=True) for i, h in enumerate(null): if i < n: obs = make_observable() obs.set_evolution(nil=True) obs.set_initial(y0=lambda x: h[obs.X[x]]) sys[f'harmonic_{i}'] = obs sys = gds.couple(sys) gds.render(sys, n_spring_iters=1000, title=f'L{k}-harmonics', **kwargs)
def euler_vortex_street(): ''' Vortex street translation in the inviscid model. x-periodic hexagonal lattice. ''' # m, n = 4, 20 # G = gds.hexagonal_lattice(m, n) # speed = 1 # # G = gds.contract_pairs(G, [((0, j), (n, j)) for j in range(1, 2*m)]) # # G = gds.remove_pos(G) # velocity, pressure = fluid_projected.euler(G) # y0 = np.zeros(velocity.ndim) # for j in range(n-1): # if j == 5: # e = ((j, m), (j, m+1)) # y_e = np.zeros(velocity.ndim) # y_e[velocity.X[e]] = 1 # y_f = speed * velocity.curl_face@y_e # y_e = velocity.curl_face.T@y_f # y0 += y_e m, n = 3, 20 G = gds.square_lattice(m, n) speed = 1 velocity, pressure = fluid_projected.euler(G) y0 = np.zeros(velocity.ndim) for j in [m // 2]: i = 5 e = ((i, j), (i + 1, j)) y_e = np.zeros(velocity.ndim) y_e[velocity.X[e]] = 1 y_f = speed * velocity.curl_face @ y_e y0 += velocity.curl_face.T @ y_f velocity.set_initial(y0=lambda x: y0[velocity.X[x]]) velocity.advect() sys = gds.couple({ 'velocity': velocity, 'vorticity': velocity.project(gds.GraphDomain.faces, lambda v: v.curl()), 'advective': velocity.project(gds.GraphDomain.edges, lambda v: -v.advect()), 'pressure': pressure, # 'divergence': velocity.project(gds.GraphDomain.nodes, lambda v: v.div()), }) gds.render(sys, canvas=gds.grid_canvas(sys.observables.values(), 3), edge_max=0.6, dynamic_ranges=True, edge_colors=True, edge_palette=cc.bgy, n_spring_iters=2000)
def scalar_advection_kinds_test(): conc1, flow1 = advection_on_triangles(periodic=True) # conc1, flow1 = advection_on_circle() conc2, flow2 = advection_on_triangles(periodic=True, kind='lie') # conc2, flow2 = advection_on_circle() sys = gds.couple({ 'conc1': conc1, 'flow1': flow1, 'div1': flow1.project(GraphDomain.nodes, lambda v: v.div()), 'conc2': conc2, 'flow2': flow2, 'div2': flow2.project(GraphDomain.nodes, lambda v: v.div()), }) gds.render(sys, canvas=gds.grid_canvas(sys.observables.values(), 3), dynamic_ranges=True, node_size=.05, title='Advection of a Gaussian concentration')
def test_orientation(): G = gds.hexagonal_lattice(3, 4) # G = gds.random_planar_graph(100, 0.2) eq1 = gds.face_gds(G) eq1.set_evolution(nil=True) eq1.set_initial(y0=lambda x: 0.5) eq2 = gds.node_gds(G) eq2.set_evolution(nil=True) sys = gds.couple({ 'eq1': eq1, 'eq2': eq2, }) gds.render(sys, face_orientations=True)
def ns_cycle_test(): n = 30 G = gds.directed_cycle_graph(n) velocity = gds.edge_gds(G) mu = 0 # viscosity print(velocity.X.keys()) D = np.zeros((velocity.ndim, velocity.ndim)) L = -D.T @ D IV = np.zeros((velocity.ndim, velocity.ndim)) edge_pairs = zip( zip(chain([n - 2, n - 1], range(n - 2)), chain([n - 1], range(n - 1))), zip(chain([n - 1], range(n - 1)), range(n))) for idx, (e_i, e_j) in enumerate(edge_pairs): print(e_i, e_j) i, j = velocity.X[e_i], velocity.X[e_j] D[i, i] = -1 D[i, j] = 1 IV[j, idx] = 1 # print(D) # D = -velocity.incidence # Either incidence or dual derivative seems to work Dm = relu(-D) Dp = relu(D) F = Dm.T @ Dp - Dp.T @ Dm # pdb.set_trace() def dvdt(t, v): A = np.multiply(F.T, v).T + np.multiply(F, v) return -A @ v + mu * L @ v velocity.set_evolution(dydt=dvdt) bump = 2 * stats.norm().pdf(np.linspace(-4, 4, n)) # v0 = -IV @ bump # v0 = IV @ rotate(bump, 10) v0 = IV @ (bump - rotate(bump, n // 2)) velocity.set_initial(y0=lambda e: v0[velocity.X[e]]) sys = gds.couple({ 'velocity': velocity, # 'gradient': velocity.project(gds.GraphDomain.edges, lambda v: D @ v.y), # 'laplacian': velocity.project(gds.GraphDomain.edges, lambda v: -D.T @ D @ v.y), # 'dual': velocity.project(gds.GraphDomain.nodes, lambda v: v.y), # 'L1': velocity.project(PointObservable, lambda v: np.abs(v.y).sum()), # 'L2': velocity.project(PointObservable, lambda v: np.linalg.norm(v.y)), # 'min': velocity.project(PointObservable, lambda v: v.y.min()), }) gds.render(sys, canvas=gds.grid_canvas(sys.observables.values(), 3), edge_max=3, dynamic_ranges=False)
def schrodinger(G: nx.Graph, V: Callable, psi0: Callable, **kwargs): re, im = gds.node_gds(G), gds.node_gds(G) V_arr = np.array([V(x) for x in re.X]) def f(t, y): psi = re.y + 1j*im.y return 1j * (re.laplacian(psi) - V_arr*psi) re.set_evolution(dydt=lambda t, y: np.real(f(t, y))) re.set_initial(y0=lambda x: np.real(psi0(x))) im.set_evolution(dydt=lambda t, y: np.imag(f(t, y))) im.set_initial(y0=lambda x: np.imag(psi0(x))) sys = gds.couple({ 'real': re, 'imag': im, }) gds.render(sys, dynamic_ranges=True, node_palette=cc.bmy, n_spring_iters=1000, **kwargs)
def render2(): viscosity, density = 1., 1e-2 p1, v1 = sq_couette_ivp(viscosity, density) p2, v2 = tri_couette_ivp(viscosity, density) p3, v3 = hex_couette_ivp(viscosity, density) sys = gds.couple({ 'velocity_sq': v1, 'velocity_tri': v2, 'velocity_hex': v3, 'flow_material_derivative_sq': v1.project(PointObservable, lambda v: np.abs(viscosity * v.laplacian() - p1.grad()).sum()), 'flow_material_derivative_tri': v2.project(PointObservable, lambda v: np.abs(viscosity * v.laplacian() - p2.grad()).sum()), 'flow_material_derivative_hex': v3.project(PointObservable, lambda v: np.abs(viscosity * v.laplacian() - p3.grad()).sum()), }) gds.render(sys, canvas=gds.grid_canvas(sys.observables.values(), 3), edge_max=0.6, dynamic_ranges=True, min_rng_size=1e-2)
def SIR_model( G, dS=0.1, dI=0.5, dR=0.0, # Diffusive terms muS=0.1, muI=0.3, muR=0.1, # Death rates Lambda=0.5, # Birth rate beta=0.2, # Rate of contact gamma=0.2, # Rate of recovery initial_population=100, patient_zero=None, **kwargs): ''' Reaction-Diffusion SIR model Based on Huang et al, https://www.researchgate.net/publication/281739911_The_reaction-diffusion_system_for_an_SIR_epidemic_model_with_a_free_boundary ''' susceptible = gds.node_gds(G, **kwargs) infected = gds.node_gds(G, **kwargs) recovered = gds.node_gds(G, **kwargs) susceptible.set_evolution(dydt=lambda t, y: dS * susceptible.laplacian( ) - muS * susceptible.y - beta * susceptible.y * infected.y + Lambda) infected.set_evolution( dydt=lambda t, y: dI * infected.laplacian() + beta * susceptible.y * infected.y - muI * infected.y - gamma * infected.y) recovered.set_evolution(dydt=lambda t, y: dR * recovered.laplacian() + gamma * infected.y - muR * recovered.y) if patient_zero is None: patient_zero = random.choice(list(G.nodes())) print(patient_zero) susceptible.set_initial(y0=lambda x: initial_population) infected.set_initial(y0=lambda x: 1 if x == patient_zero else 0.) sys = gds.couple({ 'Susceptible': susceptible, 'Infected': infected, 'Recovered': recovered }) return sys
def render(): # p, v = voronoi_poiseuille() p, v = sq_poiseuille() # p1, v1 = sq_poiseuille() # p2, v2 = tri_poiseuille() # p3, v3 = hex_poiseuille() # v = v3 sys = gds.couple({ 'velocity': v, # 'velocity_square': v1, # 'velocity_tri': v2, # 'velocity_hex': v3, 'pressure': p, # 'pressure_square': p1, # 'pressure_tri': p2, # 'pressure_hex': p3, 'vorticity': v.project(gds.GraphDomain.faces, lambda v: v.curl()), # 'vorticity_square': v1.project(gds.GraphDomain.faces, lambda v: v.curl()), # 'vorticity_tri': v2.project(gds.GraphDomain.faces, lambda v: v.curl()), # 'vorticity_hex': v3.project(gds.GraphDomain.faces, lambda v: v.curl()), # 'div_square': v1.project(gds.GraphDomain.nodes, lambda v: v.div()), # 'div_tri': v2.project(gds.GraphDomain.nodes, lambda v: v.div()), # 'div_hex': v3.project(gds.GraphDomain.nodes, lambda v: v.div()), # 'divergence': v.project(gds.GraphDomain.nodes, lambda v: v.div()), # 'laplacian_square': v1.project(gds.GraphDomain.edges, lambda v: v.laplacian()), # 'laplacian_tri': v2.project(gds.GraphDomain.edges, lambda v: v.laplacian()), # 'laplacian_hex': v3.project(gds.GraphDomain.edges, lambda v: v.laplacian()), # 'dd*': v.project(gds.GraphDomain.edges, lambda v: v.dd_()), # 'd*d': v.project(gds.GraphDomain.edges, lambda v: v.d_d()), 'energy': v.project(PointObservable, lambda v: (v.y**2).sum()), 'momentum': v.project(PointObservable, lambda v: np.abs(v.y).sum()), }) gds.render(sys, canvas=gds.grid_canvas(sys.observables.values(), 3), edge_max=0.6, dynamic_ranges=True, plot_width=900, node_size=0.04)
def self_advection_circle(): n = 10 G = nx.Graph() G.add_nodes_from(list(range(n))) G.add_edges_from(list(zip(range(n), [n-1] + list(range(n-1))))) flow = gds.edge_gds(G) flow.set_evolution(dydt=lambda t, y: -flow.advect()) # flow.set_initial(y0=dict_fun({(2,3): 1.0, (3,4): 1.0}, def_val=0.)) def init_flow(e): if e == (2,3): return 1.5 elif e == (0,n-1): return -1.0 return 1.0 flow.set_initial(y0=init_flow) flow.advect() sys = gds.couple({ 'flow': flow, 'advective': flow.project(gds.GraphDomain.edges, lambda y: -y.advect()), }) gds.render(sys, edge_max=0.5)
def show_leray(G, v: Callable = None, **kwargs): ''' Show Leray decomposition of a vector field. ''' if v is None: v = lambda x: np.random.uniform(1, 2) orig = gds.edge_gds(G) orig.set_evolution(nil=True) orig.set_initial(y0=v) div_free = orig.project(GraphDomain.edges, lambda u: u.leray_project()) curl_free = orig.project(GraphDomain.edges, lambda u: u.y - u.leray_project()) sys = gds.couple({ 'original': orig, 'original (div)': orig.project(GraphDomain.nodes, lambda u: u.div()), 'original (curl)': orig.project(GraphDomain.faces, lambda u: u.curl()), 'div-free': div_free, 'div-free (div)': div_free.project( GraphDomain.nodes, lambda u: orig.div(u.y)), # TODO: chaining projections? 'div-free (curl)': div_free.project(GraphDomain.faces, lambda u: orig.curl(u.y)), 'curl-free': curl_free, 'curl-free (div)': curl_free.project(GraphDomain.nodes, lambda u: orig.div(u.y)), 'curl-free (curl)': curl_free.project(GraphDomain.faces, lambda u: orig.curl(u.y)), }) gds.render(sys, n_spring_iters=1000, canvas=gds.grid_canvas(sys.observables.values(), 3), title='Leray decomposition', min_rng_size=1e-3, **kwargs)
def solve(): if os.path.isdir(folder): shutil.rmtree(folder) os.mkdir(folder) for N in n_triangles: os.mkdir(f'{folder}/{N}') G = gds.triangular_lattice(m=1, n=N) N_e = len(G.edges()) y0 = initial_flow(G, scale_distribution=scale_distribution) for KE in energies: V, P = euler(G) y0_ = y0 * np.sqrt(N_e * KE / np.dot(y0, y0)) V.set_initial(y0=lambda e: y0_[V.X[e]]) sys = gds.couple({'V': V, 'P': P}) time, data = sys.solve(T, dt) with open(f'{folder}/{N}/{KE}.npy', 'wb') as f: np.save(f, data['V'])
def plot_beltrami(): if not os.path.exists(save_path): raise Exception('no data') sys = dict() fig_N, fig_M = 0, 0 with open(save_path, 'rb') as f: data = cloudpickle.load(f) fig_N, fig_M = len(data), len(data[next(iter(data))]) for N, subdata in sorted(data.items(), key=lambda x: x[0]): for i in subdata: print((N, i)) u = subdata[i] G = gds.triangular_lattice(m=1, n=N) flow = gds.edge_gds(G) flow.set_evolution(nil=True) flow.set_initial(y0=lambda x: u[flow.X[x]]) sys[f'{N}_{i}'] = flow sys = gds.couple(sys) canvas = gds.grid_canvas(sys.observables.values(), fig_M) gds.render(sys, canvas=canvas, edge_max=0.6, dynamic_ranges=True)
def render_edge_diffusion(v): sys = gds.couple({ 'velocity': v, 'divergence': v.project(gds.GraphDomain.nodes, lambda v: v.div()), 'curl': v.project(gds.GraphDomain.faces, lambda v: v.curl()), 'd*d': v.project(gds.GraphDomain.edges, lambda v: -v.curl_face.T @ v.curl_face @ v.y), 'dd*': v.project(gds.GraphDomain.edges, lambda v: v.dirichlet_laplacian @ v.y), 'L1': v.project(gds.GraphDomain.edges, lambda v: v.laplacian()), }) gds.render(sys, edge_max=0.6, dynamic_ranges=True, canvas=gds.grid_canvas(sys.observables.values(), 3))
def render1(): viscosity, density = 1., 1e-2 p, v = sq_couette_ivp(viscosity, density) # p, v = tri_couette_ivp(viscosity, density) # p, v = hex_couette_ivp(viscosity, density) # components = dict() # for (name, G) in p.G.lattice_components.items(): # components[name] = v.project(G, lambda v: v) # components[f'{name}_energy'] = components[name].project(PointObservable, lambda v: (v.y ** 2).sum(), min_rng=0.1) # components[f'{name}_momentum'] = components[name].project(PointObservable, lambda v: v.y.sum(), min_rng=0.1) sys = gds.couple({ 'velocity': v, 'pressure': p, 'vorticity': v.project(GraphDomain.faces, lambda v: v.curl()), 'mass flux': v.project(GraphDomain.edges, lambda v: viscosity * v.laplacian() - p.grad()), 'total mass flux': v.project(PointObservable, lambda v: np.abs(viscosity * v.laplacian() - p.grad()).sum()), 'divergence': v.project(GraphDomain.nodes, lambda v: v.div()), }) gds.render(sys, canvas=gds.grid_canvas(sys.observables.values(), 3), edge_max=0.6, dynamic_ranges=True, min_rng_size=1e-2)
def edge_diffusion_comp(): v1 = square_edge_diffusion() v2 = tri_edge_diffusion() v3 = hex_edge_diffusion() sys = gds.couple({ 'flow_square': v1, 'flow_tri': v2, 'flow_hex': v3, 'curl_square': v1.project(gds.GraphDomain.faces, lambda v: v.curl()), 'curl_tri': v2.project(gds.GraphDomain.faces, lambda v: v.curl()), 'curl_hex': v3.project(gds.GraphDomain.faces, lambda v: v.curl()), }) gds.render(sys, canvas=gds.grid_canvas(sys.observables.values(), 3), edge_max=0.6, dynamic_ranges=True)
def fluid_test(velocity, pressure=None, columns=3, **kwargs): if hasattr(velocity, 'advector'): advector = velocity.advector # TODO: hacky else: advector = lambda v: v.advect() freqs, spec_fun = edge_power_spectrum(velocity.G) obs = { 'velocity': velocity, 'divergence': velocity.project(gds.GraphDomain.nodes, lambda v: v.div()), # 'vorticity': velocity.project(gds.GraphDomain.faces, lambda v: v.curl()), # 'diffusion': velocity.project(gds.GraphDomain.edges, lambda v: v.laplacian()), # 'tracer': lagrangian_tracer(velocity), # 'advective': velocity.project(gds.GraphDomain.edges, lambda v: -advector(v)), # 'leray projection': velocity.project(gds.GraphDomain.edges, lambda v: v.leray_project()), 'L1': velocity.project(PointObservable, lambda v: np.abs(v.y).sum()), 'power spectrum': velocity.project(VectorObservable, lambda v: spec_fun(v.y), freqs.tolist()), # 'power L2': velocity.project(PointObservable, lambda v: np.sqrt(spec_fun(v.y).sum())), 'L2': velocity.project(PointObservable, lambda v: np.sqrt(np.dot(v.y, v.y))), # 'dK/dt': velocity.project(PointObservable, lambda v: np.dot(v.y, -advector(v))), # 'dK/dt': velocity.project(PointObservable, lambda v: np.dot(v.y, -advector(velocity) - pressure.grad())), } if pressure != None: obs['pressure'] = pressure # obs['pressure_grad'] = pressure.project(gds.GraphDomain.edges, lambda p: -p.grad()) sys = gds.couple(obs) gds.render(sys, canvas=gds.grid_canvas(sys.observables.values(), columns), edge_max=0.6, dynamic_ranges=True, **kwargs)
if x[0] == n-1: return -0.2 return None pressure.set_constraints(dirichlet=pressure_values) def no_slip(x): if x[0][1] == x[1][1] == 0 or x[0][1] == x[1][1] == m-1: return 0. return None velocity.set_constraints(dirichlet=no_slip) return velocity, pressure if __name__ == '__main__': gds.set_seed(1) # v, p = poiseuille() # v, p = von_karman_projected() G = gds.triangular_lattice(m=1, n=3) v, p = fluid_projected.random_euler(G, 10) sys = gds.couple({'v': v, 'p': p}) def run(): global sys try: while True: sys.step(1e-2) print(sys.t) except KeyboardInterrupt: return cProfile.run('run()', 'out.prof') prof = pstats.Stats('out.prof') prof.sort_stats('time').print_stats(40)
def von_karman(): m = 20 n = 50 gradP = 80.0 inlet_v = 20.0 outlet_p = 0.0 G, (l, r, t, b) = gds.triangular_lattice(m, n, with_boundaries=True) tb = set(t.nodes()) | set(b.nodes()) lr = set(l.nodes()) | set(r.nodes()) v_free = lr - tb e_free = set(gds.edge_domain(G, lr)) e_normal = set(nx.edge_boundary(G, lr)) j, k = 8, m // 2 # Introduce occlusion obstacle = [ (j, k), (j + 1, k), (j + 2, k), # (j, k+1), # (j, k-1), # (j-1, k), # (j+1, k+1), # (j+1, k-1), # (j, k+2), # (j, k-2), ] obstacle_boundary = gds.utils.flatten([G.neighbors(n) for n in obstacle]) obstacle_boundary = gds.edge_domain(G, obstacle_boundary) G.remove_nodes_from(obstacle) # G.remove_edges_from(list(nx.edge_boundary(G, l, l))) # G.remove_edges_from(list(nx.edge_boundary(G, [(0, 2*i+1) for i in range(m//2)], [(1, 2*i) for i in range(m//2+1)]))) # G.remove_edges_from(list(nx.edge_boundary(G, r, r))) # G.remove_edges_from(list(nx.edge_boundary(G, [(n//2, 2*i+1) for i in range(m//2)], [(n//2, 2*i) for i in range(m//2+1)]))) velocity, pressure = fluid.navier_stokes(G, viscosity=10, v_free=v_free, e_free=e_free, e_normal=e_normal) pressure.set_constraints(dirichlet=gds.combine_bcs( {n: gradP / 2 for n in l.nodes}, {n: -gradP / 2 for n in r.nodes} # {n: 0 for n in l.nodes} # {(n//2+1, j): outlet_p for j in range(n)} )) gradation = np.linspace(-0.1, 0.1, m + 1) velocity.set_constraints(dirichlet=gds.combine_bcs( # {((0, i), (1, i)): inlet_v + gradation[i] for i in range(1, m)}, # {((n//2, i), (n//2+1, i)): inlet_v - gradation[i] for i in range(1, m)}, # {((n//2-1, 2*i+1), (n//2, 2*i+1)): inlet_v - gradation[2*i+1] for i in range(0, m//2)}, {e: 0 for e in obstacle_boundary}, gds.zero_edge_bc(t), gds.zero_edge_bc(b), )) sys = gds.couple({ 'velocity': velocity, # 'divergence': velocity.project(gds.GraphDomain.nodes, lambda v: v.div()), # 'vorticity': velocity.project(gds.GraphDomain.faces, lambda v: v.curl()), 'pressure': pressure, }) gds.render(sys, canvas=gds.grid_canvas(sys.observables.values(), 3), edge_max=0.6, dynamic_ranges=True, edge_palette=cc.bgy)