#!/usr/local/bin/python3.2 # In this program the user changes the position of a point in the # control plane by clicking on the buttons. # The horizontal line in the control plane represents a line where the coordinate $a$ is constant. # The potential function is shown in the middle panel and the right panel represents the slice # of the equilibrium surface corresponding to the value of $a$. # The current state of the system is represented in both panels by a red dot. # # I used ActivePython and ActiveTcl dowboaded (free) from ActiveState at # http://www.activestate.com/activetcl?gclid=CPPy3p3DvbUCFY9AMgodgWQAkA # Modern Tkinter for busy developers 13.6 and # http://www.tkdocs.com/tutorial/canvas.html # are good references. import sys from tkinter import * from tkinter import ttk from solve_the_cubic import solve def V(a,b,u): return u**4/4+a*u**2/2+b*u def V_u(a,b,u): return u**3+a*u+b def Z(a,u): return -u**3-a*u table=False def table_entry(a,b,u): ss="a={:5.2f} b={:5.2f} u={:5.2f} V={:5.2f} V_u={:5.2f}" return ss.format(a,b,u,V(a,b,u),V_u(a,b,u)) if table: print(table_entry(-3,2,1.1)) print(table_entry(-3,2,1)) print(table_entry(-3,2,-2)) print(table_entry(-3,2,-2.1)) print(table_entry(-3,-2,-1)) print(table_entry(-3,-2,-1.1)) print(table_entry(-3,-2,2)) print(table_entry(-3,-2,2.1)) sys.exit(0) #scaling canvas_width=380; canvas_height=500 #######################Draw in the uV plane ########################### # constants for ab_plane. Note a=3, b=2 ==> 4a^3=27b^2 a_min=-3.1; a_max= 1.0; b_min=-2.1; b_max= 2.1 def ab2tk(a,b): y=canvas_height-int(canvas_height*(a-a_min)/(a_max-a_min)) # a axis is vertical x=int(canvas_width*(b-b_min)/(b_max-b_min)) # b axis is horizonatal return (x,y) def draw_horizontal(a): global b_min,b_max x_0,y_0=ab2tk(a,b_min) x_1,y_1=ab2tk(a,b_max) #print("draw_horizontal: a={:5.2f} b_min={:5.2f} b_max={:5.2f}".format(a,b_min,b_max)) ab_plane.delete("line") ab_plane.create_line(x_0,y_0,x_1,y_1,fill="blue",tags="line") def draw_cusp(): for s in (-1,1): delta_t=s*1.1/100 t_0=0.0; for n in range(101): t_1=t_0+delta_t a_0=-3*t_0**2; b_0=2*t_0**3 # 27a^3=t^6=4b^2 a_1=-3*t_1**2; b_1=2*t_1**3 # -4a^3=t^6=27b^2 x_0,y_0=ab2tk(a_0,b_0); x,y=ab2tk(a_1,b_1) ab_plane.create_line(x_0,y_0,x,y,fill="red") t_0=t_1 #print("draw_cusp: a={:5.2f}, b={:5.2f}, x={:d}, y={:,d})".format(a_0,b_0,x,y)) def ab_point(a,b): x,y=ab2tk(a,b) #print("ab_point: a,b=({:3.2f},{:3.2f})".format(a,b)) #print("-- (x,y)=({:d},{:d})".format(x,y)) ab_plane.delete("point") ab_plane.create_oval(x-4,y-4,x+4,y+4,fill="red",tags=("point")) #######################Draw in the uV plane ########################### # constants for draw_quartic and draw_cubic u_min=-4.3; u_max=4.3 def uV2tk(u,V): V_min=-6.5; V_max= 3.3 x=int(canvas_width*(u-u_min)/(1.0*(u_max-u_min))) y=canvas_height-int(canvas_height*(V-V_min)/(1.0*(V_max-V_min))) return (x,y) def uv_line(u_0,V_0,u_1,V_1): x_0,y_0=uV2tk(u_0,V_0) x_1,y_1=uV2tk(u_1,V_1) uV_plane.create_line(x_0,y_0,x_1,y_1,tags="curve",width=2) def draw_quartic(): #print("quartic") global a,b, u_min,u_max #print("draw_quartic: (a,b)=({:4.2f},{:4.2f})".format(a,b)) uV_plane.delete("curve") #vertical lines seperate the three pannels uV_plane.create_line(uV2tk(u_min+0.2,-10),uV2tk(u_min+0.2,10),width=3) uV_plane.create_line(uV2tk(u_max,-10),uV2tk(u_max,10),width=3) u_0=u_min; delta_u=(u_max-u_min)/100 for n in range(101): u_1=u_0+delta_u uv_line(u_0,V(a,b,u_0),u_1,V(a,b,u_1)) u_0=u_1 #print("draw_quartic: (u,V)=({:4.2f},{:4.2f})".format(u_1,V_1)+ #" (x,y)=({:d},{:d})".format(x_1,y_1)) def uV_point(u,v): #print("uV_point: u={:5.2f}, V={:5.2f}".format(u,V(a,b,u))) x,y=uV2tk(u,v) uV_plane.delete("point") uV_plane.create_oval(x-4,y-4,x+4,y+4,fill="red",tags=("point")) def uV_points(u,v): #print("uV_point: u={:5.2f}, V={:5.2f}".format(u,V(a,b,u))) x,y=uV2tk(u,v) uV_plane.create_oval(x-4,y-4,x+4,y+4,fill="red",tags=("catastrophe")) ####################### Draw in the dVu plane ########################### def dVu2tk(dV,u): dV_min=-6.1; dV_max= 6.1 y=int(canvas_width*(u-u_min)/(0.7*(u_max-u_min))) x=canvas_height-int(canvas_height*(dV-dV_min)/(1.0*(dV_max-dV_min))) return (x,y) def dVu_line(z_0,u_0,z_1,u_1): x_0,y_0=dVu2tk(z_0,u_0) # u-axis is vertical x_1,y_1=dVu2tk(z_1,u_1) # udV_plane.create_line(x_0,y_0,x_1,y_1,fill="blue",tags="curve",width=2) def draw_cubic(): #print("cubic") global a,b, u_min, u_max udV_plane.delete("curve") u_0=u_min; delta_u=(u_max-u_min)/100 for n in range(101): u_1=u_0+delta_u dVu_line(Z(a,u_0),u_0,Z(a,u_1),u_1) u_0=u_1 def dVu_point(z,u): print("dVu_point: z={:5.2f}, u={:5.2f}".format(z,u)) x,y=dVu2tk(z,u) # u axis is vertical udV_plane.delete("point") udV_plane.create_oval(x-4,y-4,x+4,y+4,fill="red",tags=("point")) def dVu_points(z,u): print("dVu_point: z={:5.2f}, u={:5.2f}".format(z,u)) x,y=dVu2tk(z,u) # u axis is vertical udV_plane.create_oval(x-4,y-4,x+4,y+4,fill="red",tags=("catastrophe")) #---------------------------------------------- def draw(): global a draw_cusp() ab_point(a,b) draw_horizontal(a) draw_quartic() uV_point(u,V(a,b,u)) draw_cubic() dVu_point(Z(a,u),u) #*************inititialize globals********************** a=-1.0; b=0.0; u=1.0 # V_u(a,b,u)=0 #******************************************************* def draw_catastrophe(a_0,b_0,a_1,b_1): u_0=solve(-a_0/3,b_0); u_1=solve(-a_1/3,b_1) if len(u_0)==1 or len(u_1)==3: return # no catastrophe # len(u_0)==3 and len(u_1)==1 if u_0[1]-u_0[0]u_0[2]-u_0[1] and u==u_0[0]: return # no catastrophe if u==u_0[2]: v=u_0[0] else: v=u_0[2] print("catastrophe: u={:5.2f}, Z(a_0,u)={:5.2f}".format(u,Z(a_0,u))) print("catastrophe: v={:5.2f}, Z(a_0,v)={:5.2f}".format(v,Z(a_0,v))) print("catastrophe: u={:5.2f}, Z(a_1,u)={:5.2f}".format(u,Z(a_1,u))) print("catastrophe: v={:5.2f}, Z(a_1,v)={:5.2f}".format(v,Z(a_1,v))) #udV_plane.create_line(x_0,y_0,x_1,y_1,width=5,tags=("catastrophe")) delta=(v-u)/10.0 print("begin Catastrophe") for n in range(1,10): uV_points(u+n*delta,V(a_1,b_1,u+n*delta)) dVu_points(Z(a_0,u_1[0]),u+n*delta) print("end Catastrophe") def next_state(a_0,b_0,a_1,b_1): uV_plane.delete("catastrophe") udV_plane.delete("catastrophe") global a,b,u #print("next_state: a={:5.2f} b={:5.2f} u={:5.2f} V_u={:5.2f}".format(a,b,u,V_u(a,b,u))) u_0=solve(-a_0/3,b_0); u_1=solve(-a_1/3,b_1) #print("next_state", u_0,u_1) if len(u_1)==1: draw_catastrophe(a_0,b_0,a_1,b_1) u=u_1[0] # no choice else: # len(u_1)==3, go to closest state if abs(u-u_1[0])b_min: next_state(a,b,a,b-delta_b) #print("dec_b: a,b=({:3.2f},{:3.2f})".format(a,b)) def inc_a(): global a,b,delta_a if aa_min: next_state(a,b,a-delta_a,b) #print("dec_a: a,b=({:3.2f},{:3.2f})".format(a,b)) root = Tk() content = ttk.Frame(root, padding=(3,3,12,12)) content.grid(column=0,row=0,columnspan=9,rowspan=4) ab_plane =Canvas(content,borderwidth=2, width=canvas_width, height=canvas_height) uV_plane =Canvas(content,borderwidth=2, width=canvas_width, height=canvas_height) udV_plane =Canvas(content,borderwidth=2, width=canvas_width, height=canvas_height) button_array=Frame(content,borderwidth=2, width=canvas_width,bg="lightgray") ab_plane.grid(column=0,row=0,columnspan=3) button_array.grid(column=0,row=1,columnspan=3) # use convert to convert tex file to .gif and preview to crop quartic_formula_object=PhotoImage(file='quartic_formula.gif') uV_plane.grid(column=3,row=0,columnspan=3) quartic_formula=ttk.Label(content,image=quartic_formula_object ).grid(column=4,row=1,rowspan=1,columnspan=1,sticky=EW) cubic_formula_object=PhotoImage(file='cubic_formula.gif') udV_plane.grid(column=6,row=0,columnspan=3) cubic_formula=ttk.Label(content,image=cubic_formula_object ).grid(column=7,row=1,rowspan=1,columnspan=1,sticky=EW) left =ttk.Button(button_array, text="Decrease b", command=dec_b).grid(column=0, row=2, sticky=W) right =ttk.Button(button_array, text="Increase b", command=inc_b).grid(column=2, row=2, sticky=W) up =ttk.Button(button_array, text="Increase a", command=inc_a).grid(column=1, row=1, sticky=W) down =ttk.Button(button_array, text="Decrease a", command=dec_a).grid(column=1, row=3, sticky=W) root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) # initial picture #ab_plane.create_line(ab2tk(a_min,0.0),ab2tk(a_max,0.0)) # a-axis (vertical) #ab_plane.create_line(ab2tk(0.0,b_min),ab2tk(0.0,b_max)) # b-axis (horizontal) draw() root.mainloop()