angle_rng=angle_rng) # %% Classify the stability of fixed points df_td_exp, df_ev_exp = eqns.tau_delta(df_equil_exp, Cl_fun, Cd_fun, Clprime_fun, Cdprime_fun) df_td_spl, df_ev_spl = eqns.tau_delta(df_equil_spl, cl_fun, cd_fun, clprime_fun, cdprime_fun, angle_rng=angle_rng) # %% Stability analysis for individual squirrels df_nuni_exp, df_uni_exp, df_class_exp = eqns.classify_fp(df_td_exp) df_nuni_spl, df_uni_spl, df_class_spl = eqns.classify_fp(df_td_spl) possible_class = [ 'saddle point', 'unstable focus', 'unstable node', 'stable focus', 'stable node' ] bfbmap = [bmap[0], bmap[4], bmap[2], bmap[3], bmap[1]] # %% Spline bifurcation plot for paper rd = np.rad2deg gam_high = angle_rng[0] - pitches # closer to 0 gam_low = angle_rng[1] - pitches # closer to 90
cdprime_fun_1, angle_rng=arng) nt_td_4, nt_ev_4 = td(nt_equil_4, cl_fun_4, cd_fun_4, clprime_fun_4, cdprime_fun_4, angle_rng=arng) nt_td, nt_ev = td(nt_equil, cl_fun, cd_fun, clprime_fun, cdprime_fun, angle_rng=arngpt) _, _, nt_Class_1 = eqns.classify_fp(nt_TD_1) _, _, nt_Class_4 = eqns.classify_fp(nt_TD_4) _, _, nt_Class = eqns.classify_fp(nt_TD) _, _, nt_class_1 = eqns.classify_fp(nt_td_1) _, _, nt_class_4 = eqns.classify_fp(nt_td_4) _, _, nt_class = eqns.classify_fp(nt_td) #possible_class = ['saddle point', 'unstable spiral', 'unstable node', # 'stable spiral', 'stable node'] #bfbmap = [bmap[0], bmap[4], bmap[2], bmap[3], bmap[1]] possible_class = [ 'saddle point', 'unstable focus', 'stable focus', 'stable node' ] bfbmap = [bmap[0], bmap[4], bmap[3], bmap[1]]
angle_rng=angle_rng) # %% Classify the stability of fixed points ch_td_exp, ch_ev_exp = eqns.tau_delta(ch_equil_exp, Cl_fun, Cd_fun, Clprime_fun, Cdprime_fun) ch_td_spl, ch_ev_spl = eqns.tau_delta(ch_equil_spl, cl_fun, cd_fun, clprime_fun, cdprime_fun, angle_rng=angle_rng) # %% Stability analysis for individual squirrels ch_nuni_exp, ch_uni_exp, ch_class_exp = eqns.classify_fp(ch_td_exp) ch_nuni_spl, ch_uni_spl, ch_class_spl = eqns.classify_fp(ch_td_spl) possible_class = [ 'saddle point', 'unstable focus', 'unstable node', 'stable focus', 'stable node' ] bfbmap = [bmap[0], bmap[4], bmap[2], bmap[3], bmap[1]] # %% Spline bifurcation plot for paper rd = np.rad2deg gam_high = angle_rng[0] - pitches # closer to 0 gam_low = angle_rng[1] - pitches # closer to 90
Cdprime_fun_25, angle_rng=arng) so_td_10, so_ev_10 = td(so_equil_10, cl_fun_10, cd_fun_10, clprime_fun_10, cdprime_fun_10, angle_rng=arng) so_td_25, so_ev_25 = td(so_equil_25, cl_fun_25, cd_fun_25, clprime_fun_25, cdprime_fun_25, angle_rng=arng) _, _, so_Class_10 = eqns.classify_fp(so_TD_10) _, _, so_Class_25 = eqns.classify_fp(so_TD_25) _, _, so_class_10 = eqns.classify_fp(so_td_10) _, _, so_class_25 = eqns.classify_fp(so_td_25) possible_class = [ 'saddle point', 'unstable focus', 'unstable node', 'stable focus', 'stable node' ] bfbmap = [bmap[0], bmap[4], bmap[2], bmap[3], bmap[1]] # %% Spline bifurcation plot (deg) for paper rd = np.rad2deg gam_high = arng[0] - pitches # closer to 0
# %% Eigenvalue plot (Re vs. Re, Im vs. Im) fig, ax = plt.subplots() ax.plot(np.real(sq_ev_spl[:, 0]), np.real(sq_ev_spl[:, 1]), 'o', label=r'$Re$') ax.plot(np.imag(sq_ev_spl[:, 0]), np.imag(sq_ev_spl[:, 1]), 'o', label=r'$Im$') ax.set_xlabel(r'$\lambda_1$', fontsize=16) ax.set_ylabel(r'$\lambda_2$', fontsize=16) ax.legend(loc='best', frameon=False) rcj(ax) tl(fig) # %% Stability analysis sq_nuni_exp, sq_uni_exp, sq_class_exp = eqns.classify_fp(sq_td_exp) sq_nuni_spl, sq_uni_spl, sq_class_spl = eqns.classify_fp(sq_td_spl) possible_class = ['saddle point', 'unstable focus', 'unstable node', 'stable focus', 'stable node'] bfbmap = [bmap[0], bmap[4], bmap[2], bmap[3], bmap[1]] # %% Spline bifurcation plot fig, ax = plt.subplots() for ii, fp_kind in enumerate(possible_class): idx = np.where(sq_class_spl == fp_kind)[0] if len(idx) > 0: ax.plot(sq_equil_spl[idx, 1], sq_equil_spl[idx, 0], 'o', ms=2, label=fp_kind, c=bfbmap[ii], mec=bfbmap[ii])
def phase_plotter(afdict, pitch, lims, arng, tvec, ngrid=201, nseed=41, nseed_skip=1, quiver=False, skip=10, seed=False, timer=False, gamtest=None, extrap=None, traj=None, seedloc=None, fig=None, ax=None, acc_contour=True, nullcline_x=False, nullcline_z=False): # unpack the data cli, cdi, = afdict['cli'], afdict['cdi'] clip, cdip = afdict['clip'], afdict['cdip'] # upack axis limits vxlim, vzlim = lims from eqns import cart_eqns, cart_model if traj is None: traj = ps_traj_dp5 VXorig, VZorig, VX, VZ, ALPHA = setup_grid(ngrid, vxlim, vzlim, pitch, arng) CL = cli(ALPHA.flatten()).reshape(ALPHA.shape) CD = cdi(ALPHA.flatten()).reshape(ALPHA.shape) dVX, dVZ = cart_eqns(VX, VZ, CL, CD) AMAG = np.hypot(dVX, dVZ) AX, AZ = dVX / AMAG, dVZ / AMAG # calculation the integral curves now = time.time() # vxs, vzs, VXs, VZs, als = setup_grid(nseed, vxlim, vzlim, pitch, arng) vxseed, vzseed = seed_locations(nseed, vxlim, vzlim, pitch, arng) vxseed, vzseed = vxseed[::nseed_skip], vzseed[::nseed_skip] if seedloc is not None: vxseed = np.r_[vxseed, seedloc[:, 0]] vzseed = np.r_[vzseed, seedloc[:, 1]] odeargs = (pitch, cli, cdi) solns = [] for i in range(len(vxseed)): x0 = (0, 0, vxseed[i], vzseed[i]) soln = traj(x0, tvec, odeargs, cart_model, arng, vxlim, vzlim) solns.append(soln) if timer: print('Elapsed time: {:.3f}'.format(time.time() - now)) # equilibrium points if gamtest is not None: from eqns import pitch_bifurcation as pb from eqns import v_equil, vxvz_equil, tau_delta, classify_fp equil = pb([pitch], gamtest, cli, cdi, angle_rng=arng) thbar, gambar = equil.T vbar = v_equil(pitch + gambar, cli, cdi) vxbar, vzbar = vxvz_equil(vbar, gambar) td, ev = tau_delta(equil, cli, cdi, clip, cdip, arng) _, _, fp_class = classify_fp(td) possible_class = [ 'saddle point', 'unstable focus', 'unstable node', 'stable focus', 'stable node' ] bfbmap = [bmap[0], bmap[4], bmap[2], bmap[3], bmap[1]] if fig is None or ax is None: fig, ax = plt.subplots(figsize=(5.5, 5.125)) if quiver: ax.quiver(VX[::skip, ::skip], VZ[::skip, ::skip], AX[::skip, ::skip], AZ[::skip, ::skip], color='gray', pivot='middle', alpha=.8, edgecolor='gray', linewidths=0 * np.ones(VX[::skip, ::skip].size)) for i in range(len(solns)): ax.plot(solns[i][:, 2], solns[i][:, 3], '-', ms=2.25, c='gray', alpha=.95, lw=.5) # color=bmap[1]) if seed: ax.plot(vxseed, vzseed, 'o', ms=2.5) if gamtest is not None: for ii, fp_kind in enumerate(possible_class): idx = np.where(fp_class == fp_kind)[0] if len(idx) == 0: continue # now globalize the phase space if fp_kind == 'saddle point': # or fp_kind == 'stable node' or fp_kind == 'unstable node': tvec = np.linspace(tvec[0], 3 * tvec[-1], 6 * len(tvec)) vxpt, vzpt = vxbar[idx], vzbar[idx] solns = [] for i in range(len(vxpt)): vxs, vzs = saddle_filler(vxpt[i], vzpt[i]) for vx0, vz0 in zip(vxs, vzs): ic = (0, 0, vx0, vz0) sn1 = traj(ic, tvec, odeargs, cart_model, arng, vxlim, vzlim) sn2 = traj(ic, -tvec, odeargs, cart_model, arng, vxlim, vzlim) solns.append(sn1) solns.append(sn2) # plot the globalized saddles for i in range(len(solns)): ax.plot(solns[i][:, 2], solns[i][:, 3], '-', c=bfbmap[ii]) # plot the equilibrium point ax.plot(vxbar[idx], vzbar[idx], 'o', ms=7, c=bfbmap[ii], zorder=200) if acc_contour: ax.contourf(VX, VZ, AMAG, [0, .1], colors=[bmap[3]], alpha=.2) # ax.contourf(VX, VZ, dVZ, [0, .1], colors=[bmap[4]], alpha=.2) if extrap is not None and extrap[0] is not None: ax.contourf(VX, VZ, np.array(ALPHA < extrap[0]).astype(np.int), [.5, 1.5], colors='gray', alpha=.1) if extrap is not None and extrap[1] is not None: ax.contourf(VX, VZ, np.array(ALPHA > extrap[1]).astype(np.int), [.5, 1.5], colors='gray', alpha=.1) # plot the nullclines if nullcline_x: ax.contour(VX, VZ, dVX, [0], colors=[bmap[3]], alpha=1, zorder=100) if nullcline_z: ax.contour(VX, VZ, dVZ, [0], colors=[bmap[3]], alpha=1, zorder=100) ax.set_xlim(vxlim[0], vxlim[1]) ax.set_ylim(vzlim[1], vzlim[0]) ax.xaxis.set_label_position('top') ax.xaxis.tick_top() ax.set_xlabel(r"$\hat{v}_x$", fontsize=20) ax.set_ylabel(r"$\hat{v}_z $", fontsize=20, rotation=0) ax.set_aspect('equal', adjustable='box') # these need to be square ax.set_xticks([0, .25, .5, .75, 1, 1.25]) ax.set_yticks([0, -.25, -.5, -.75, -1, -1.25]) ax.set_xticklabels(['0', '', '', '', '', '1.25']) ax.set_yticklabels(['0', '', '', '', '', '-1.25']) [ttl.set_size(18) for ttl in ax.get_xticklabels()] [ttl.set_size(18) for ttl in ax.get_yticklabels()] rcj(ax, ['bottom', 'right']) tl(fig) return fig, ax
angle_rng=sn_angle_rng) # %% Classify the stability of fixed points sn_td_exp, sn_ev_exp = eqns.tau_delta(sn_equil_exp, Cl_fun, Cd_fun, Clprime_fun, Cdprime_fun, angle_rng=sn_angle_rng) sn_td_spl, sn_ev_spl = eqns.tau_delta(sn_equil_spl, cl_fun, cd_fun, clprime_fun, cdprime_fun, angle_rng=sn_angle_rng) # %% Classification of fixed points sn_nuni_exp, sn_uni_exp, sn_class_exp = eqns.classify_fp(sn_td_exp) sn_nuni_spl, sn_uni_spl, sn_class_spl = eqns.classify_fp(sn_td_spl) possible_class = ['saddle point', 'unstable focus', 'unstable node', 'stable focus', 'stable node'] bfbmap = [bmap[0], bmap[4], bmap[2], bmap[3], bmap[1]] # %% Acceleration along terminal manifold when we have a saddle point sad_idx = np.where(sn_class_spl == 'saddle point')[0] sad_pitch, sad_gamma = sn_equil_spl[sad_idx].T # we have some double saddle points below theta =2 deg; remove these sad_idx = np.where(sad_pitch >= np.deg2rad(2))[0] sad_pitch, sad_gamma = sad_pitch[sad_idx], sad_gamma[sad_idx]