def build(self): data = np.random.random((10, 10)) # Create the widgets. We need a vertical box to arrange the navigation toolbar hbox = BoxLayout() vbox = BoxLayout(orientation="vertical") label = Label(text="Click on the plot as many times as you want!") # Create the figure. fig = Figure() axes = fig.add_subplot() axes.imshow(data) canvas = FigureCanvasKivyAgg(fig) nav = NavigationToolbar2Kivy(canvas) # Add them to a container. vbox.add_widget(canvas) vbox.add_widget(nav.actionbar) hbox.add_widget(label) hbox.add_widget(vbox) # Add the callback of the canvas. canvas.mpl_connect("button_press_event", on_canvas_click) canvas.draw() # Return the top container. This can be any widget return hbox
class YoungSlitScreen(Screen): slt_number = NumericProperty(0) is_source_on = BooleanProperty(False) def __init__(self, **kwargs): super(YoungSlitScreen, self).__init__(**kwargs) def yspseudo_init(self): #temps inicial (0, evidentment) self.t = 0 self.source_on = False #recinte i discretitzat self.dt = 1 / 20 self.dl = 2 * self.dt self.Nx = 301 self.Ny = 301 global Nx_inty, Ny_inty Nx_inty = self.Nx Ny_inty = self.Ny #visualització del recinte que apareix a l'App self.h_display = int(self.Ny / 3) self.w_display = int(2 * self.Nx / 3) #variables de l'ona self.w = 2 * pi self.c = 1.4 self.amp = 2.5 self.tau = 2 * pi / self.w self.Ntau = int(1 + self.tau / self.dt) self.rao = (self.c * self.dt / self.dl)**2 #variables paret self.sgm_max = 0.02615 self.m = 1.54 #llistes de l'ona i la paret en el recinte self.a = np.zeros((self.Nx, self.Ny, 3)) self.a2 = np.zeros((self.Nx, self.Ny, self.Ntau)) self.inty = np.zeros((self.Nx, self.Ny, 3)) self.sgm = np.zeros((self.Nx, self.Ny)) self.sgm_wall = np.zeros((self.Nx, self.Ny)) self.sgm_det = np.zeros((self.Nx, self.Ny)) #font self.s = np.zeros((self.Nx, self.Ny)) #slits self.Nslt = 0 self.w_slt = 8 #gruix i posició de les parets self.x_wall = int(self.Nx / 4) self.w_wall = int(self.Nx / 30) self.w_det = int(self.Nx / 3) global w_det_ys w_det_ys = self.w_det self.slit_presence = np.zeros((self.Nx, self.Ny)) self.slit_presence[self.x_wall, :] = 1 self.separation = int(self.Ny / 10) #coef d'absorció a les parets del detector for k in range(self.w_det): self.sgm_det[self.Nx-1-k,0+k:self.Ny-1-k]=\ self.sgm_max*((self.w_det-k)/self.w_det)**self.m self.sgm_det[self.x_wall:self.Nx-k,k]=\ self.sgm_max*((self.w_det-k)/self.w_det)**self.m self.sgm_det[self.x_wall:self.Nx-k,self.Ny-1-k]=\ self.sgm_max*((self.w_det-k)/self.w_det)**self.m ##########################PRIMER DIBUIX################### #creem la figura recipient del plot imshow self.main_fig, self.axs = plt.subplots(2, sharex=True, sharey=True) #L'associem amb kivy self.main_canvas = FigureCanvasKivyAgg(self.main_fig) self.box1.add_widget(self.main_canvas, 1) #Plot de l'ona i de l'intensitat self.wave_visu = self.axs[0] self.inty_visu = self.axs[1] self.at = self.a[:, :, 2] self.it = self.inty[:, :, 2] #Dibuix de les figures self.cmap = plt.get_cmap('Reds') self.cmap.set_under('k', alpha=0) #diagrama d'ones self.wave_visu_im=self.wave_visu.imshow(\ self.at.transpose()[int((self.Ny-self.h_display)/2):\ int((self.Ny+self.h_display)/2), 0:self.w_display] ,vmax=4,vmin=-4,origin='lower', extent=(0,int(self.w_display*self.dl),0,int(self.h_display*self.dl))) #representació de la paret al diagrama d'ones self.wave_slit_im=self.wave_visu.imshow(\ self.slit_presence.transpose()[int((self.Ny-self.h_display)/2):\ int((self.Ny+self.h_display)/2), 0:self.w_display] ,vmax=1,vmin=0.5,origin='lower',cmap=self.cmap, extent=(0,int(self.w_display*self.dl),0,int(self.h_display*self.dl))) #diagrama d'intensitat self.inty_visu_im=self.inty_visu.imshow(\ self.it.transpose()[int((self.Ny-self.h_display)/2):\ int((self.Ny+self.h_display)/2), 0:self.w_display] ,vmax=5,origin='lower',cmap='gray', extent=(0,int(self.w_display*self.dl),0,int(self.h_display*self.dl))) #representació de la paret al diagrama d'intensitat self.inty_slit_im=self.inty_visu.imshow(\ self.slit_presence.transpose()[int((self.Ny-self.h_display)/2):\ int((self.Ny+self.h_display)/2), 0:self.w_display] ,vmax=1,vmin=0.5,origin='lower',cmap=self.cmap, extent=(0,int(self.w_display*self.dl),0,int(self.h_display*self.dl))) self.main_canvas.draw() self.main_canvas.mpl_connect('resize_event', partial(self.resize_kivy)) def resize_kivy(self, *largs): """Aquesta funció és trucada cada cop que la finestra canvia de tamany. Cada cop que això passa, les coordenades (en pixels) dels cantons del plot imshow canvien de lloc. Aquests són molt importants sobretot pel joc, per tant, cal tenir-nos ben localitzats.""" #Aquesta funció de matplotlib ens transforma els cantons de coordenades Data # a display (pixels) self.wave_cantonsnew = self.wave_visu.transData.transform([ (0, 0), (0, int(self.h_display * self.dl)), (int(self.w_display * self.dl), int(self.h_display * self.dl)), (int(self.w_display * self.dl), 0) ]) self.inty_cantonsnew = self.inty_visu.transData.transform([ (0, 0), (0, int(self.h_display * self.dl)), (int(self.w_display * self.dl), int(self.h_display * self.dl)), (int(self.w_display * self.dl), 0) ]) def ys_schedule_fired(self): "Ara, definim l'update, a partir d'aqui farem l'animació" self.schedule = Clock.schedule_interval(self.plotysev, self.dt) #integral per trapezis, on h és el pas, i f, una llista amb els valors de #la funció a inetgrar, és una llista 3D d'una funció 2D amb dependència temps #i com que estem integrant en el temps ens retorna una llista 2D def trapezis(self, h, f): val = (np.sum(f[:, :, 0:-1], axis=2) + np.sum(f[:, :, 1:], axis=2)) * h / 2 return val #funció de la font def p_s(self, t, amp, w): val = amp * np.sin(w * t) return val #plot young slit evolution def plotysev(self, dt): k = 2 if self.source_on == True: self.s[1, :] = self.p_s(self.t, self.amp, self.w) if self.source_on == False: self.s[:, :] = 0 """càlculs que fa el programa a cada pas""" slt_i = np.zeros((self.Nslt + 2), dtype=int) slt_f = np.zeros((self.Nslt + 2), dtype=int) slt_n = np.linspace(1, self.Nslt, self.Nslt, dtype=int) wall_presence = np.zeros((self.Ny), dtype=int) if self.Nslt == 2: #posicio del final i l'inici de cada escletxa, ara amb separació variable slt_i[1]=int(self.Ny/2)-int(self.separation/2)-\ int(self.w_slt/2) slt_i[2]=int(self.Ny/2)+int(self.separation/2)-\ int(self.w_slt/2) slt_f[1]=int(self.Ny/2)-int(self.separation/2)+\ int(self.w_slt/2) slt_f[2]=int(self.Ny/2)+int(self.separation/2)+\ int(self.w_slt/2) slt_f[0] = 0 slt_f[self.Nslt + 1] = self.Ny slt_i[self.Nslt + 1] = self.Ny else: #posicio del final i l'inici de cada escletxa slt_i[1:self.Nslt+1]=int(self.Ny/2)-int(self.h_display/2)-\ int(self.w_slt/2)+slt_n[:]*int(self.h_display/(1+self.Nslt)) slt_f[1:self.Nslt+1]=int(self.Ny/2)-int(self.h_display/2)+\ int(self.w_slt/2)+slt_n[:]*int(self.h_display/(1+self.Nslt)) slt_f[0] = 0 slt_f[self.Nslt + 1] = self.Ny slt_i[self.Nslt + 1] = self.Ny #les escletxes van de splt_i a splt_f-1, en aquests punts no hi ha paret, # a slpt_f ja hi ha paret for n in range(1, self.Nslt + 2): wall_presence[slt_f[n - 1]:slt_i[n]] = 1 wall_presence[slt_i[n]:slt_f[n]] = 0 # matriu que, amb el gruix de la paret com a nombre de files, ens diu si # hi ha paret o escletxes a cada una de les y(representades en les columnes) wall_presence = np.tile(np.array([wall_presence], dtype=int), (self.w_wall, 1)) #matriu que diu com de "dins" som a la paret wall_n = np.linspace(1, self.w_wall, self.w_wall) wall_ny = np.tile( np.array([wall_n], dtype=int).transpose(), (1, self.Ny)) #valors de coeficient d'absorció a les parets self.sgm_wall[self.x_wall-self.w_wall:self.x_wall,:]=wall_presence[:,:]\ *self.sgm_max*((wall_ny[:,:])/self.w_wall)**self.m #llista per a l'última capa de la paret, on l'amplitud d'ona és 0 self.wave_presence = np.ones((self.Nx, self.Ny)) self.wave_presence[self.x_wall, :] = (1 - wall_presence[0, :]) self.sgm = self.sgm_wall + self.sgm_det #resolució de l'equació d'ones a cada temps a l'interior del recinte self.a[1:-1,1:-1,k]=\ (self.rao*(self.a[2:,1:-1,k-1]+self.a[0:-2,1:-1,k-1]\ +self.a[1:-1,2:,k-1]+self.a[1:-1,0:-2,k-1]\ -4*self.a[1:-1,1:-1,k-1])+self.s[1:-1,1:-1]\ +2*self.a[1:-1,1:-1,k-1]-self.a[1:-1,1:-1,k-2]\ +self.sgm[1:-1,1:-1]*self.a[1:-1,1:-1,k-2]/(2*self.dt))\ /(1+self.sgm[1:-1,1:-1]/(2*self.dt))\ *self.wave_presence[1:-1,1:-1] #condicions periòdiques de contorn a les parets superior i inferior self.a[1:self.x_wall,0,k]=\ (self.rao*(self.a[2:self.x_wall+1,0,k-1]+self.a[0:self.x_wall-1,0,k-1]\ +self.a[1:self.x_wall,1,k-1]+self.a[1:self.x_wall,self.Ny-1,k-1]\ -4*self.a[1:self.x_wall,0,k-1])+self.s[1:self.x_wall,0]\ +2*self.a[1:self.x_wall,0,k-1]-self.a[1:self.x_wall,0,k-2]\ +self.sgm[1:self.x_wall,0]*self.a[1:self.x_wall,0,k-2]/(2*self.dt))\ /(1+self.sgm[1:self.x_wall,0]/(2*self.dt))\ *self.wave_presence[1:self.x_wall,0] self.a[1:self.x_wall,self.Ny-1,k]=\ (self.rao*(self.a[2:self.x_wall+1,self.Ny-1,k-1]\ +self.a[0:self.x_wall-1,self.Ny-1,k-1]\ +self.a[1:self.x_wall,0,k-1]+self.a[1:self.x_wall,self.Ny-2,k-1]\ -4*self.a[1:self.x_wall,self.Ny-1,k-1])+self.s[1:self.x_wall,self.Ny-1]\ +2*self.a[1:self.x_wall,self.Ny-1,k-1]\ -self.a[1:self.x_wall,self.Ny-1,k-2]\ +self.sgm[1:self.x_wall,self.Ny-1]\ *self.a[1:self.x_wall,self.Ny-1,k-2]/(2*self.dt))\ /(1+self.sgm[1:self.x_wall,self.Ny-1]/(2*self.dt))\ *self.wave_presence[1:self.x_wall,self.Ny-1] #calculs de la intensitat self.a2[:, :, :-1] = self.a2[:, :, 1:] self.a2[:, :, self.Ntau - 1] = self.a[:, :, k] * self.a[:, :, k] self.inty[:, :, k] = self.trapezis(self.dt, self.a2) / self.tau #preparació del següent pas self.a[:, :, :-1] = self.a[:, :, 1:] self.t = self.t + self.dt self.slit_presence = 1 - self.wave_presence """Representació a cada pas""" #eliminar l'anterior self.wave_visu_im.remove() self.wave_slit_im.remove() self.inty_visu_im.remove() self.inty_slit_im.remove() #Posar el nou self.at = self.a[:, :, 2] self.it = self.inty[:, :, 2] global intensitat_llum intensitat_llum = self.it #diagrama d'ones self.wave_visu_im=self.wave_visu.imshow(\ self.at.transpose()[int((self.Ny-self.h_display)/2):\ int((self.Ny+self.h_display)/2), 0:self.w_display] ,vmax=4,vmin=-4,origin='lower', extent=(0,int(self.w_display*self.dl),0,int(self.h_display*self.dl))) self.wave_slit_im=self.wave_visu.imshow(\ self.slit_presence.transpose()[int((self.Ny-self.h_display)/2):\ int((self.Ny+self.h_display)/2), 0:self.w_display] ,vmax=1,vmin=0.5,origin='lower',cmap=self.cmap, extent=(0,int(self.w_display*self.dl),0,int(self.h_display*self.dl))) #diagrama d'intensitat self.inty_visu_im=self.inty_visu.imshow(\ self.it.transpose()[int((self.Ny-self.h_display)/2):\ int((self.Ny+self.h_display)/2), 0:self.w_display] ,vmax=5,origin='lower',cmap='gray', extent=(0,int(self.w_display*self.dl),0,int(self.h_display*self.dl))) self.inty_slit_im=self.inty_visu.imshow(\ self.slit_presence.transpose()[int((self.Ny-self.h_display)/2):\ int((self.Ny+self.h_display)/2), 0:self.w_display] ,vmax=1,vmin=0.5,origin='lower',cmap=self.cmap, extent=(0,int(self.w_display*self.dl),0,int(self.h_display*self.dl))) #I utilitzar-lo self.main_canvas.draw() def ys_schedule_cancel(self): self.schedule.cancel() def add_slit(self): if self.Nslt < 5: self.Nslt += 1 else: pass def remove_slit(self): if self.Nslt > 0: self.Nslt -= 1 else: pass def inc_slt_width(self): if (self.Nslt * self.w_slt) < self.h_display: self.w_slt += 2 else: pass def dec_slt_width(self): if self.w_slt > 0: self.w_slt -= 2 else: pass def change_source_state(self): self.t = 0 if self.source_on == False: self.source_on = True else: self.source_on = False def clear_waves(self): self.a = np.zeros((self.Nx, self.Ny, 3)) def inc_separation(self): if (self.Nslt * self.w_slt + self.separation) < self.h_display: self.separation += 2 else: pass def dec_separation(self): if self.separation > 0: self.separation -= 2 else: pass
class PaquetScreen(Screen): "Això és la part més important de la app. Introduïrem la pantalla inicial" #Les propietats s'han de definir a nivell de classe (millor). Per tant, #les definim aquí. quadrat = ObjectProperty(None) position = ListProperty(None) def __init__(self, **kwargs): "Unim la clase amb la paraula self" super(PaquetScreen, self).__init__(**kwargs) #Aquesta linia uneix keyboard amb request keyboard self._keyboard = Window.request_keyboard(self._keyboard_closed, self) #self._keyboard.bind(on_key_down=self._on_keyboard_down) def gpseudo_init(self): "Iniciem el primer dibuix de l'aplicació" #Variables globals... global Vvec, avec, cvec, psi0, normavec, mode ################### PARAMETRES DE LA CAIXA,DISCRETITZAT,PARTICULA######## self.L = 3 self.xa = -self.L self.xb = self.L #Discretitzat self.tb = 0.1 self.ta = 0 self.dx = 0.05 self.dt = 0.02 self.Nx = np.int((2 * self.L) / self.dx) #particula i constants físiques self.m = 1 self.hbar = 1 self.t_total = 0. self.x0 = 0. self.y0 = 0. self.px = 0 self.py = 0 #Comptador de moments self.i = 0 #parametre del discretitzat self.r = (self.dt / (4 * (self.dx**2))) * (self.hbar / self.m) #Canvia el text del interior de la caixa 'parameters' amb els parametr #es inicials escollits self.box3.dxchange.text = "dx={}".format(self.dx) self.box3.longitudchange.text = "L={}".format(self.L) self.box3.dtchange.text = "dt={}".format(self.dt) #################### PARAMETRES NECESSARIS PER EFECTUAR ELS CALCULS###### #################### POTENCIALS #Potencial estandar(mode=0) self.Vvecestandar = np.array([[ ck.Vharm(self.xa + i * self.dx, self.xa + j * self.dx, self.xb, self.xb) for i in range(self.Nx + 1) ] for j in range(self.Nx + 1)], dtype=np.float64) #Potencial slit(mode=1) self.yposslitd = np.int(self.Nx * (4.75 / 10)) self.yposslitu = np.int(self.Nx * (5.25 / 10)) self.xposslit = np.int(self.Nx / 3) self.x0slit = self.L / 2 self.y0slit = 0. self.Vvecslit = np.copy(self.Vvecestandar) self.Vvecslit[0:self.yposslitd, self.xposslit] = 100000 self.Vvecslit[self.yposslitu:self.Nx, self.xposslit] = 100000 ##################### PAQUETS #Paquet propi del mode estandar self.psiestandar = np.array([[ ck.psi0f(-self.L + i * self.dx, -self.L + j * self.dx, 0.25, self.px, self.py, self.x0, self.y0) for i in range(self.Nx + 1) ] for j in range(self.Nx + 1)]) #dtype=np.complex128) #Paquet propi del mode slit self.psislit = np.array([[ ck.psi0f(-self.L + i * self.dx, -self.L + j * self.dx, 0.25, self.px, self.py, self.x0slit, self.y0slit) for i in range(self.Nx + 1) ] for j in range(self.Nx + 1)]) ##################### MODES #mode: 0, estandard # 1,slit # 2,disparo(encara no està fet) #definm el mode inicial tal que: self.Vvec = self.Vvecestandar self.psi0 = self.psiestandar #Ens indica en quin mode estem self.mode = 0 #Per últim, construïm les matrius molt importants per efectuar els càlculs. self.avec, self.cvec = ck.ac(self.r, self.Vvec, self.Nx) ##########################PRIMER CÀLCUL ENERGIA##### #Calculem la matriu densitat inicial self.normavec = ck.norma(self.psi0, self.Nx) #Calculem moments i energia inicials i els posem al lloc corresponent self.norma0 = ck.trapezis(self.xa, self.xb, self.dx, np.copy(self.normavec)) self.energy0 = ck.Ham(self.xa, self.xb, self.dx, np.copy(self.psi0)) self.box3.normachange.text = 'Norma={0:.3f}'.format(self.norma0) self.box3.energychange.text = 'Energia={0:.3f}'.format(self.energy0) ##########################PRIMER DIBUIX################### #creem la figura recipient del plot imshow self.main_fig = plt.figure() #L'associem amb kivy self.main_canvas = FigureCanvasKivyAgg(self.main_fig) self.box1.add_widget(self.main_canvas, 1) #Plot principal self.visu = plt.axes() self.visu_im = self.visu.imshow(self.normavec, origin={'lower'}, extent=(-self.L, self.L, -self.L, self.L)) #Posició de la figura self.visu.set_position([0, 0.15, 0.8, 0.8]) #Dibuixem tot lo dit self.main_canvas.draw() ##################################MATPLOTLIB EVENTS/RESIZING #self.main_canvas.mpl_connect('motion_notify_event', motionnotify) #Conectem l'event resize de matplotlib amb la funció resize_kivy. #Aquesta útlima ens permet saber on estan els cantons de la caixa en #coordenades de pixels de la finestra en un primer instant (ja que quan # kivy obre matplotlib per primer cop fa ja un resize), i tambe posteriorment, # cada cop que fem el resize. Això ens podria ser útil en algún moment. self.main_canvas.mpl_connect('resize_event', resize) self.main_canvas.mpl_connect('resize_event', partial(self.resize_kivy)) ################################POTENCIAL MODE/Widget de dibuix self.setcordpress = np.array([]) self.setcordrelease = np.array([]) self.paint = MyPaintWidget() #No pinta a no ser que estigui activat. self.paint.pause_paint = True self.box1.add_widget(self.paint) ###############################PROPIETATS DEL QUADRAT AMB EL QUE JUGUEM self.quadrat.pos = [800, 800] self.play_game = False ###################################BUTONS DE LA CAIXA 2################### #Aquests butons varian el menu principal del joc #Aquest activa la funció que activa,atura, o reseteja el calcul self.box2.add_widget( Button(text='Play', on_press=partial(self.compute))) self.box2.add_widget(Button(text='Pause', on_press=partial(self.pause))) self.box2.add_widget(Button(text='Reset', on_press=partial(self.reset))) self.box2.add_widget( Button(text='Standard', on_press=partial(self.standard))) self.box2.add_widget(Button(text='Slit', on_press=partial(self.slit))) self.box2.add_widget(Button(text='Game', on_press=partial(self.gameon))) #####################################PAUSESTATE self.pause_state = True ##Ara venen tot el seguït de funcions que utilitzarem conjuntament amb els #parametres definits a g_init ##############################RESIZING############################ #1.Resize_kivy #Funcions que s'ocupen del tema resize: def resize_kivy(self, *largs): """Aquesta funció és trucada cada cop que la finestra canvia de tamany. Cada cop que això passa, les coordenades (en pixels) dels cantons del plot imshow canvien de lloc. Aquests són molt importants sobretot pel joc, per tant, cal tenir-nos ben localitzats.""" #Aquesta funció de matplotlib ens transforma els cantons de coordenades Data # a display (pixels) self.cantonsnew = self.visu.transData.transform([(-3, -3), (-3, 3), (3, 3), (3, -3)]) print(self.cantonsnew) ################################FUNCIONS DE CALCUL/FLUX################## #1.g_schedule_fired #2.plotpsiev #3.compute(play) #4.pause #5.reset def g_schedule_fired(self): "Ara, definim l'update, a partir d'aqui farem l'animació" self.schedule = Clock.schedule_interval(self.plotpsiev, 1 / 60.) def plotpsiev(self, dt): "Update function that updates psi plot" if self.pause_state == False: #Primer de tot, representem el primer frame if (self.i) == 0: self.compute_parameters() #Animation #Lanimació consisteix en elimanr primer el que teniem abans self.normavec = ck.norma(self.psi0, self.Nx) self.visu_im.remove() #Posar el nou self.visu_im = self.visu.imshow(self.normavec, origin={'lower'}, extent=(-self.L, self.L, -self.L, self.L)) #I utilitzar-lo self.main_canvas.draw() #CALCUL #Tot següit fem el càlcul del següent step self.psi0 = ck.Crannk_stepm(self.psi0, self.avec, self.cvec, self.r, self.Vvec, self.dt, self.Nx, self.i) #Canviem el temps self.t_total = self.t_total + (self.dt) / 2. self.box3.tempschange.text = 'temps={0:.3f}'.format(self.t_total) #Videojoc, coses del videojoc if self.play_game == True: self.maxvalue = np.amax(self.normavec) self.llindar = self.maxvalue / 20. if self.normavec[self.pos_discret[0], self.pos_discret[1]] > self.llindar: print('Touched') #Cada 31 pasos de temps calculem el temps: self.i += 1 def compute(self, *largs): """Quan es clica el butó play, s'activa aquesta funció, que activa el calcul""" self.pause_state = False def pause(self, *largs): """Aquesta funció para el càlcul del joc""" self.pause_state = True def reset(self, *largs): """Aquesta funció reseteja el paquet i el potencial inicials. Segons el mode inicial en el que ens trobem, es resetejara un o l altre.""" if self.pause_state == True: #Segons el mode, reseteja un potencial o un paquet diferent if self.mode == 0: self.psi0 = self.psiestandar self.Vvec = self.Vvecestandar if self.mode == 1: self.psi0 = self.psislit self.Vvec = self.Vvecslit #Parametres que s'han de tornar a resetejar self.i = 0 self.px = 0 self.py = 0 self.t_toal = 0. #Rseteja la imatge self.normavec = ck.norma(self.psi0, self.Nx) self.visu_im.remove() self.visu_im = self.visu.imshow(self.normavec, origin={'lower'}, extent=(-self.L, self.L, -self.L, self.L)) self.main_canvas.draw() #Canviem els parametre en pantalla tambe self.box3.tempschange.text = 'temps=0.' self.box3.pxchange.text = 'px=0' self.box3.pychange.text = 'py=0' #####################################CHANGE PARAMETERs################## #Fucnions que s'encarregar del canvi efectiu dels parametres #1.changep def changep(self, add_px, add_py, *largs): """Funció que respon als buto + i - que varia el moment inicial del paquet. Per que aquest canvi sigui efectiu, hem de canviar tambe el propi paquet.""" #if selfpause==True #Canvi el moment en pantalla self.px += add_px self.py += add_py print(self.px, self.py) self.box3.pxchange.text = 'px={}'.format(self.px) self.box3.pychange.text = 'py={}'.format(self.py) #Canvi del moment efectiu if self.mode == 0: self.psi0 = np.array([[ ck.psi0f(-self.L + i * self.dx, -self.L + j * self.dx, 0.25, self.px, self.py, 0., 0.) for i in range(self.Nx + 1) ] for j in range(self.Nx + 1)]) if self.mode == 1: self.psi0 = np.array([[ ck.psi0f(-self.L + i * self.dx, -self.L + j * self.dx, 0.25, self.px, self.py, self.x0slit, self.y0slit) for i in range(self.Nx + 1) ] for j in range(self.Nx + 1)]) ################################# POTENCIAL MODE ######################### #Aquestes funcions juntament amb el widget MyPaintWidget porten la posibilitat #de poder dibuixar un potencial. #1.editorfun(start) #2.editorstop(stop) #3.Activatepaint(pinta només si self.paint.pause_paint==False) #4.Potpress(apunta les coordenades on es pren el potencial) #5.Potrelease(apunta les coordenades on es solta el potencial) #6.modifypot(Agafa aquests dos punts i els ajunta, tot creaunt un potencial # infinit al mig. #7.clear (reseteja el potencial que s'hagui dibuixat, amb tot el que implica) def editorfun(self, *largs): """Aquesta funció es l'encarregada d'activar el mode editor. Activa l'event de matplotlib que detecta la entrada al propi plot o la sortida, i l'enllaça amb la funció activatepaint""" #Controla que només es pogui dibuixar dins la figura self.cidactivate = self.main_canvas.mpl_connect( 'axes_enter_event', partial(self.activatepaint, 1)) self.ciddesactivate = self.main_canvas.mpl_connect( 'axes_leave_event', partial(self.activatepaint, 0)) def editorstop(self, *largs): """Aquesta funció desactiva totes les conexions activades a editorfun, i per tant, desactiva el mode editor""" self.main_canvas.mpl_disconnect(self.cidactivate) self.main_canvas.mpl_disconnect(self.ciddesactivate) def activatepaint(self, n, *largs): """Aquesta funció s'encarrega d'activar el widget Paint(que dona la capactiat de pintar en pantalla, només quan el cursor està dins del plot). També activa quatre funcions i les conecta amb les accions d'apretar i soltar el click dret del mouse per, d'aquesta manera, enregistar on s'ha apretat.""" if n == 1: self.paint.pause_paint = False self.cid1 = self.main_canvas.mpl_connect('button_press_event', press) self.cid2 = self.main_canvas.mpl_connect('button_press_event', partial(self.potpress)) self.cid3 = self.main_canvas.mpl_connect('button_release_event', release) self.cid4 = self.main_canvas.mpl_connect('button_release_event', partial(self.potrelease)) print('painting') else: self.paint.pause_paint = True self.main_canvas.mpl_disconnect(self.cid1) self.main_canvas.mpl_disconnect(self.cid2) self.main_canvas.mpl_disconnect(self.cid3) self.main_canvas.mpl_disconnect(self.cid4) def potpress(self, *largs): """Funció que s'encarrega de guardar en coordenades de data el lloc on s'ha apretat al plot""" self.setcordpress = np.append(self.setcordpress, cordpress) print(self.setcordpress) def potrelease(self, *largs): """Funció que s'encarrega de guardar en coordenades de data el lloc on s'ha soltat al plot.""" self.setcordrelease = np.append(self.setcordrelease, cordrelease) print(self.setcordrelease) def modifypot(self, *largs): """Aquesta funció s'aplica quan es clika el buto apply. Durant el període que s'ha dibuixat, totes les lineas de potencial s'han en- registrat a les variables self.csetcorpress i setcordreleas. Aquestes estan en coordenades de self. data i les hem de passar al discretitzat.""" #Variables on guardem les dates del dibuix vecpress = self.setcordpress vecrelease = self.setcordrelease #linias dibuixades=vecsize/2 vecsize = np.int(vecpress.size) #Aquí guardarem els resultats. transformvectorx = np.array([], dtype=int) transformvectory = np.array([], dtype=int) #Coloquem una guasiana al voltant del potencial que pintem. La sigma^2 farem que #sigui del mateix tamany que el pas s2vec = self.dx valorVec = 10000. #Bucle de conversió de les dades for i in range(0, vecsize, 2): #Establim noms de variables index = i x0 = vecpress[index] y0 = vecpress[index + 1] x1 = vecrelease[index] y1 = vecrelease[index + 1] Vecgaussia = self.potential_maker(x0, y0, x1, y1, valorVec, s2vec) #I el sumem... self.Vvec += Vecgaussia #Coloquem una petita gaussiana al voltant de cada punt de sigma*2=self.dx/2 #self.Vvec=Vvec #Modifiquem els respectius ac,vc #self.Vvec=Vvec print(self.Vvec) self.avec, self.cvec = ck.ac(self.r, self.Vvec, self.Nx) print('Applied!') def gaussian_maker(self, x, y, x0, y0, x1, y1, value, s2, *largs): """Introduïm aquí la gaussiana per cada x e y... x0,y0,x1,y1, son els dos punts que uneixen la recta dibuixada. Utilitzarem les rectes perpen- diculars en aquestes a cada punt per dissenyar aquest potencial.""" #Primer de tot, definim el pendent de la recta que uneix els dos punts if (x1 - x0) == 0.: x_c = x0 y_c = y else: m = (y1 - y0) / (x1 - x0) if m == 0: y_c = y0 x_c = x else: x_c = 0.5 * (x0 + x - (y0 - y) / m) y_c = m * (x_c - x0) + y0 #definim condicio per si posar-hi gaussiana o no: if x0 - self.dx < x_c < x1 + self.dx: #Obteim el punt en y #Ara només hem de calcular quant val la gaussiana: Vvecgauss = value * (1. / (np.sqrt(s2 * 2. * np.pi))) * np.exp( -(0.5 / s2) * ((x - x_c)**2 + (y - y_c)**2)) else: Vvecgauss = 0. return Vvecgauss def potential_maker(self, x0, y0, x1, y1, value, s2, *largs): Vvecgauss1 = np.array([[ self.gaussian_maker(self.xa + i * self.dx, self.xa + j * self.dx, x0, y0, x1, y1, value, s2) for i in range(self.Nx + 1) ] for j in range(self.Nx + 1)]) return Vvecgauss1 def clear(self, *largs): """Aquesta funció neteja el canvas i tot els canvis introduïts tan al potencial com a les coordenades del potencial. """ self.paint.canvas.clear() self.setcordpress = np.array([]) self.setcordrelease = np.array([]) if self.mode == 0: self.Vvec = self.Vvecestandar if self.mode == 1: self.Vvec = self.Vvecslit ############################## MODES#################################### #Aquestes funcions s'activen quan clikem self o slit i s'encarreguen de que #resetejar tot el que hi ha en pantalla (si estan en un mode difent al seu #propi) i posar el mode escollit #1.standard(mode 0) #2.slit(mode slit) def standard(self, *largs): """Funció que retorna el mode estandard en tots els aspectes: de càlcul, en pantalla, etf...""" if self.mode == 0: pass else: self.Vvec = self.Vvecestandar self.psi0 = self.psiestandar #Llevem les líneas que hi pogui haver if self.mode == 1: self.lineslit1.remove() self.lineslit2.remove() #Això es un reset, pensar fer-ho amb el reset. #Canviem la pantalla i el mode: self.i = 0 #Rseteja la imatge self.normavec = ck.norma(self.psi0, self.Nx) self.visu_im.remove() #Posar el nou self.visu_im = self.visu.imshow(self.normavec, origin={'lower'}, extent=(-self.L, self.L, -self.L, self.L)) #I utilitzar-lo self.main_canvas.draw() #Canviem el temps tambe self.t_total = 0. self.box3.tempschange.text = 'temps=0.' self.px = 0 self.py = 0 self.box3.pxchange.text = 'px=0' self.box3.pychange.text = 'py=0' self.mode = 0 def slit(self, *largs): """Quan activem aquest buto, canviem el paquet de referencia i el potencial de referència i ho deixem en el mode slit. Aquest mode correspon amb el número 1.""" self.mode = 1 self.Vvec = self.Vvecslit self.psi0 = self.psislit """Pintem tot lo dit i afegim una líniea que es correspón amb el potencial, fix en aquest mode.""" #Rseteja la imatge self.normavec = ck.norma(self.psi0, self.Nx) self.visu_im.remove() #Posar el nou self.visu_im = self.visu.imshow(self.normavec, origin={'upper'}, extent=(-self.L, self.L, -self.L, self.L)) self.lineslit1 = self.visu.axvline(x=-self.L + self.xposslit * self.dx, ymin=0, ymax=0.475, color='white') self.lineslit2 = self.visu.axvline( x=-self.L + self.xposslit * self.dx, ymin=0.525, ymax=1, color='white', ) #I utilitzar-lo self.main_canvas.draw() ################################### COMPUTE PARAMETES##################### #Aquestes funcions efectuan càlculs de diferents parametres. De moment, # només de l'energia i la norma #1.compute_parameters def compute_parameters(self, *largs): """Aquesta funció s'encarrega de calcular la norma i la energia del paquet en un cert instant t i despres l'ensenya a pantalla.""" #Calculem moments i energia inicials i els posem al lloc corresponent self.normavec = ck.norma(self.psi0, self.Nx) self.norma0 = ck.trapezis(self.xa, self.xb, self.dx, np.copy(self.normavec)) self.energy0 = ck.Ham(self.xa, self.xb, self.dx, np.copy(self.psi0)) self.box3.normachange.text = 'Norma={0:.3f}'.format(self.norma0) self.box3.energychange.text = 'Energia={0:.3f}'.format(self.energy0) ##################################### JOC ########################## #Funcions relacionades amb el propi joc #1._keyboard_closed #2._on_keyboard_down #3.on_position #4.on_game def _keyboard_closed(self): """No se ben bé que fa però es necessària""" self._keyboard.unbind(on_key_down=self._on_keyboard_down) self._keyboard = None def _on_keyboard_down(self, keyboard, keycode, text, modifiers, *largs): """Aquesta funció s'ocupa de conectar el moviment del quadrat amb el teclat. És a dir, conecta l'esdeveniment de teclejar amb el de fer que el quadrat avanci un pas. A l'hora, també imposa els limits on el quadrat es pot moure. """ #Definim els limits superior e inferior xliminf = np.int(self.cantonsnew[0, 0]) xlimsup = np.int(self.cantonsnew[2, 0]) yliminf = np.int(self.cantonsnew[0, 1]) ylimsup = np.int(self.cantonsnew[1, 1]) #defim el pas pas = 10 #definim a quina distància s'ha de parar el rectangle. w = self.quadrat.width h = self.quadrat.height #Hem de pensar que la posició es defineix a la cantonada inferior esquerre #del rectangle dist = 5 #Conexions events amb moviment quadrat if keycode[1] == 'w': if self.quadrat.y + dist + h > ylimsup: pass else: self.quadrat.y += pas self.position = self.quadrat.pos return True if keycode[1] == 's': if self.quadrat.y - dist < yliminf: pass else: self.quadrat.y -= pas self.position = self.quadrat.pos #self.position=self.quadrat.position #print(self.quadrat.position) return True if keycode[1] == 'd': if self.quadrat.x + dist + w > xlimsup: pass else: self.quadrat.x += pas self.position = self.quadrat.pos return True elif keycode[1] == 'a': if self.quadrat.x - dist < xliminf: pass else: self.quadrat.x -= pas self.position = self.quadrat.pos return True def on_position(self, quadrat, pos): """Cada cop que el quadrat canvia de posició, això es notifica aquí. Utilitzarem aquesta funció (que està anclada a una propietat) per fer el canvi de coordenades pixels matplotlib-data matplotlib. Tot seguït, sabent on es troba el paquet, podem saber a sobre de quin valor de densitat del paquet es troba i definir que passa quan es troba en segons quines situacions...""" #Utilitzem la transformació inversa que ens porta de pixels matplotlib # a dades matplotlib. inv_data = self.visu.transData.inverted() #Posició del centre del quadrat pos_data = inv_data.transform((pos[0] + self.quadrat.width / 2, pos[1] + self.quadrat.height / 2)) #Un cop tenim la posició del centre del quadrat en coordenades data, les #pasem a coord del discretitzat: self.pos_discret = np.array([(pos_data[0] + self.L) / self.dx, (pos_data[1] + self.L) / self.dx], dtype=int) #Busquem el valor màxim de normavec cada cop que es mou el paquet #definim un llindar a partir del qual el quadrat detecta el paquet self.maxvalue = np.amax(self.normavec) self.llindar = self.maxvalue / 20. if self.normavec[self.pos_discret[0], self.pos_discret[1]] > self.llindar: print('Touched') def gameon(self, *largs): """Aquesta funció es l'encarregada de posar el joc en marxa. Col·loca el quadradet a algún lloc on es pogui veure (una mica cutre però ja ho canviaras). Uneix la funció teclat amb el moviment del quadrat, i varia el mode del joc.""" if self.play_game == False: self.play_game = True self.quadrat.x = np.int( (-self.cantonsnew[0, 0] + self.cantonsnew[2, 0]) / 5. + self.cantonsnew[0, 0]) self.quadrat.y = np.int( 3 * (-self.cantonsnew[0, 1] + self.cantonsnew[1, 1]) / 4. + self.cantonsnew[0, 1]) self._keyboard.bind(on_key_down=self._on_keyboard_down) else: self.play_game = False self.quadrat.x = 800 self.quadrat.y = 600 self._keyboard.unbind(on_key_down=self._on_keyboard_down)