class NEBExplorer(QtGui.QMainWindow): def __init__(self, parent=None, system=None, app=None): QtGui.QMainWindow.__init__(self, parent=parent) self.ui = UI() self.ui.setupUi(self) self.system = system self.app = app self.mdi = QtGui.QMdiArea(self) self.setCentralWidget(self.mdi) self.nebrunner = NEBRunner(app, system) self.nebrunner.on_update_gui.connect(self.update) self.nebrunner.on_run_started.connect(self.run_started) self.nebrunner.on_run_finished.connect(self.run_finished) # from dlg_params import EditParamsWidget # w = QtGui.QDockWidget("NEB parameters", self) # w.setWidget(EditParamsWidget(self, # self.system.params.double_ended_connect.local_connect_params.NEBparams)) # self.addDockWidget(QtCore.Qt.RightDockWidgetArea, w) # # self.editparams = w # self.energies = NEBEnergyWidget() self.view_energies = self.new_view("Energies", self.energies, QtCore.Qt.TopDockWidgetArea) self.view_distances = self.new_view("Distances", NEBDistanceWidget(), QtCore.Qt.TopDockWidgetArea) self.view_k = self.new_view("k", NEBTimeseries(attrname="k"), QtCore.Qt.BottomDockWidgetArea) self.view_nimages = self.new_view("nimages", NEBTimeseries(attrname="nimages"), QtCore.Qt.BottomDockWidgetArea) self.view_rms = self.new_view("rms", NEBTimeseries(attrname="rms", yscale='log'), QtCore.Qt.BottomDockWidgetArea) self.show3d = Show3DWithSlider() self.view_3d = QtGui.QDockWidget("NEB parameters", self) self.view_3d.setWidget(self.show3d) self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.view_3d) #self.view_3d.setFloating(True) self.view_3d.hide() self.show3d.setSystem(self.system) self.show3d.on_frame_updated.connect(self.set_current_frame) self.centralWidget().hide() def run_started(self): self.ui.actionRun.setEnabled(False) self.ui.actionReset.setEnabled(False) self.ui.actionTS.setEnabled(False) def run_finished(self): self.ui.actionRun.setEnabled(True) self.ui.actionReset.setEnabled(True) self.ui.actionTS.setEnabled(True) def set_current_frame(self, index, sender=None): self.energies.highlight_frame(index) def new_view(self, title, widget, pos=QtCore.Qt.RightDockWidgetArea): child = QtGui.QDockWidget(title, self) child.setWidget(widget) self.addDockWidget(pos, child) self.nebrunner.on_update_gui.connect(widget.update_gui) return child def new_neb(self, coords1, coords2, path=None, run=True): self.coords1 = coords1.copy() self.coords2 = coords2.copy() self.initial_path=path self.nebrunner.run(coords1, coords2, path=path, run=run) def toggle_view(self, view, show): if show: view.show() else: view.hide() def update(self, nebrunner): self.show3d.setCoordsPath(nebrunner.path) def on_actionRun_triggered(self, checked=None): if checked is None: return self.nebrunner.continue_run() def on_actionReset_triggered(self, checked=None): if checked is None: return self.nebrunner.run(self.coords1, self.coords2, run=False, path=self.initial_path) def on_actionParams_triggered(self, checked=None): if checked is None: return if not hasattr(self, "paramsdlg"): self.paramsdlg = DlgParams(self.system.params.double_ended_connect.local_connect_params.NEBparams, parent=self) self.paramsdlg.show() def on_actionSave_triggered(self, checked=None): if checked is None: return dialog = QtGui.QFileDialog(self) dialog.setFileMode(QtGui.QFileDialog.AnyFile) dialog.selectFile("path.pickle") dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave); if(not dialog.exec_()): return filename = dialog.selectedFiles()[0] pickle.dump(self.nebrunner.path, open(filename, "w")) def on_actionLoad_triggered(self, checked=None): if checked is None: return dialog = QtGui.QFileDialog(self) dialog.setFileMode(QtGui.QFileDialog.AnyFile) dialog.setAcceptMode(QtGui.QFileDialog.AcceptOpen); if(not dialog.exec_()): return filename = dialog.selectedFiles()[0] self.initial_path = pickle.load(open(filename)) self.nebrunner.run(self.coords1, self.coords2, run=False, path=self.initial_path) def on_actionRms_toggled(self, checked): self.toggle_view(self.view_rms, checked) def on_actionE_toggled(self, checked): self.toggle_view(self.view_energies, checked) def on_actionS_toggled(self, checked): self.toggle_view(self.view_distances, checked) def on_actionK_toggled(self, checked): self.toggle_view(self.view_k, checked) def on_actionNimages_toggled(self, checked): self.toggle_view(self.view_nimages, checked) def on_action3D_toggled(self, checked): self.toggle_view(self.view_3d, checked) def on_actionTS_triggered(self, checked=None): if checked is None: return if not hasattr(self, "local_connect_explorer"): self.local_connect_explorer = ConnectExplorerDialog(self.system, self.app, parent=self) self.local_connect_explorer.show() self.local_connect_explorer.set_nebrunner(self.nebrunner)
class NormalmodeBrowser(QtGui.QMainWindow): """ the GUI for exploring normal modes """ def __init__(self, parent=None, system=None, app=None): QtGui.QMainWindow.__init__(self, parent=parent) self.ui = UI() self.ui.setupUi(self) self.ui.view3D.setSystem(system) self.system = system self._params = dict() self._params["amplitude"]=1.0 self._params["remove_known_zeroev"]=True export = self._params["export"] = dict() export["nframes"]=100 self._params["nframes"] = 30 self.app = app self.current_selection = None self.ui.actionShow_energies.setChecked(False) self.ui.mplwidget.hide() self.ui.actionRun.setVisible(False) def set_coords(self, coords, normalmodes=None): """ set the coordinates for which the normal modes will be computed """ self.coords = coords self.normalmodes = normalmodes if normalmodes is None: self._calculate_normalmodes() self._fill_normalmodes() self.ui.view3D.setCoords(coords) def _calculate_normalmodes(self): """ compute the normal modes """ # pot = self.system.get_potential() # E, g, hess = pot.getEnergyGradientHessian(self.coords) # metric = self.system.get_metric_tensor(self.coords) # freq, mode = normalmodes(hess, metric = metric) freq, mode = self.system.get_normalmodes(self.coords) mode=np.real(mode.transpose()) self.normalmodes = [] #self.normalmodes.append((fre[0], m.flatten())) for f, m in zip(freq, mode): self.normalmodes.append((f, m)) #np.dot(metric, m))) def _fill_normalmodes(self): """ populate the list of normal modes """ self.ui.listNormalmodes.clear() for n in self.normalmodes: self.ui.listNormalmodes.addItem(NormalmodeItem(n)) def on_listNormalmodes_currentItemChanged(self, newsel): """ change which normal mode we're looking at """ if newsel is None: self.currentmode = None return orthogopt = self.system.get_orthogonalize_to_zero_eigenvectors() mode = newsel.get_mode().copy() if self._params["remove_known_zeroev"]: mode = orthogopt(mode, self.coords) self.currentmode = mode self.current_selection = newsel # generate the configurations from the normal mode amp = self._params["amplitude"] vector = self.currentmode nframes = self._params["nframes"] dxlist = [amp * float(i) / nframes for i in xrange(-nframes/2,nframes/2)] coordspath = [self.coords + dx * vector for dx in dxlist] coordspath = np.array(coordspath) self.dxlist = dxlist self.coordspath = coordspath self.ui.view3D.setCoordsPath(coordspath)#, labels=labels) # self.ui.view3D.ui.btn_animate.hide() if self.ui.actionShow_energies.isChecked(): self.draw_energy_plot() def draw_energy_plot(self): """ make a plot of the energies and the energies from the harmonic approximation """ if self.current_selection is None: return dxlist = self.dxlist coordspath = self.coordspath # get the energies of the configurations pot = self.system.get_potential() energies = [pot.getEnergy(coords) for coords in coordspath] # get the energies of the harmonic approximation freq = self.current_selection.get_freq() expected_energies = np.array([ 0.5*(freq)*(dx)**2 for dx in dxlist]) expected_energies += pot.getEnergy(self.coords) # make the plot ax = self.ui.mplwidget.axes ax.clear() ax.plot(dxlist, energies, label="energy") ax.plot(dxlist, expected_energies, label="harmonic approximation") ax.legend(loc='best') ax.set_xlabel("displacement") self.ui.mplwidget.draw() def on_actionRun_toggled(self, checked=None): if checked is None: return if checked: self.ui.view3D.start_animation() else: self.ui.view3D.stop_animation() def on_actionShow_energies_toggled(self, checked=None): if checked is None: return if checked: self.ui.mplwidget.show() self.draw_energy_plot() else: self.ui.mplwidget.hide() def on_actionSave_triggered(self, checked=None): """ save the normal modes to disk """ if checked is None: return dialog = QtGui.QFileDialog(self) dialog.setFileMode(QtGui.QFileDialog.AnyFile) dialog.selectFile("mode.pickle") dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave); if(not dialog.exec_()): return filename = dialog.selectedFiles()[0] path = [] nframes = self._params["export"]["nframes"] for i in xrange(nframes): t = np.sin(i/float(nframes)*2.*np.pi) path.append(self.coords + self._params["amplitude"]*t*self.currentmode) pickle.dump(path, open(filename, "w")) def on_actionParameters_triggered(self, checked=None): """ open a dialog box to change the parameters """ if checked is None: return if not hasattr(self, "_paramsdlg"): self._paramsdlg = DlgParams(self._params, parent=self) self._paramsdlg.show()
class MyForm(QtGui.QMainWindow): def __init__(self, systemtype, parent=None): QtGui.QWidget.__init__(self) self.ui = MainWindow.Ui_MainWindow() self.ui.setupUi(self) self.listMinima = [ self.ui.listWidget, self.ui.listMinima1, self.ui.listMinima2, self.ui.listFrom ] self.systemtype = systemtype self.NewSystem() self.transition=None #try to load the pymol viewer. self.usepymol = True try: from pymol_viewer import PymolViewer self.pymolviewer = PymolViewer(self.system.load_coords_pymol) except (ImportError or NotImplementedError): self.usepymol = False #note: glutInit() must be called exactly once. pymol calls it #during pymol.finish_launching(), so if we call it again it will #give an error. On the other hand, if we're not using pymol we #must call it. from OpenGL.GLUT import glutInit glutInit() def NewSystem(self): self.system = self.systemtype() db = self.system.create_database() self.system.database = db self.system.database.onMinimumAdded=self.NewMinimum self.system.database.onMinimumRemoved=self.RemoveMinimum for l in self.listMinima: l.clear() def edit_params(self): self.paramsdlg = DlgParams(self.system.params) self.paramsdlg.show() #def save(self): # import pickle # filename = QtGui.QFileDialog.getSaveFileName(self, 'Save File', '.') # output = open(filename, "w") # pickle.dump(self.system.storage, output) def connect(self): """ connect to an existing database """ filename = QtGui.QFileDialog.getSaveFileName(self, 'Open File', '.') self.connect_db(filename) def connect_db(self, filename): db = self.system.create_database(db=filename) self.system.database = db for minimum in self.system.database.minima(): self.NewMinimum(minimum) self.system.database.onMinimumAdded=self.NewMinimum self.system.database.onMinimumRemoved=self.RemoveMinimum def SelectMinimum(self, item): print "selecting minimum", item.minimum._id, item.minimum.energy self.ui.widget.setSystem(self.system) self.ui.widget.setCoords(item.coords) self.ui.widget.setMinimum(item.minimum) self.ui.oglTS.setSystem(self.system) self.ui.oglTS.setCoords(item.coords) if self.usepymol: self.pymolviewer.update_coords([item.coords], index=1, delete_all=True) def _SelectMinimum1(self, minimum): """by minimum""" self.ui.oglPath.setSystem(self.system) self.ui.oglPath.setCoords(minimum.coords, index=1) self.ui.oglPath.setMinimum(minimum, index=1) self.neb = None if self.usepymol: self.pymolviewer.update_coords([minimum.coords], index=1) def SelectMinimum1(self, item): """called by the ui""" return self._SelectMinimum1(item.minimum) def _SelectMinimum2(self, minimum): """by minimum""" self.ui.oglPath.setSystem(self.system) self.ui.oglPath.setCoords(minimum.coords, index=2) self.ui.oglPath.setMinimum(minimum, index=2) self.neb = None if self.usepymol: self.pymolviewer.update_coords([minimum.coords], index=2) def SelectMinimum2(self, item): """called by the ui""" return self._SelectMinimum2(item.minimum) def Invert(self): coords2 = self.ui.oglPath.coords[2] self.ui.oglPath.setCoords(-coords2, 2) if self.usepymol: self.pymolviewer.update_coords([-coords2], index=2) def AlignMinima(self): coords1 = self.ui.oglPath.coords[1] coords2 = self.ui.oglPath.coords[2] align = self.system.get_mindist() dist, coords1, coords2 = align(coords1, coords2) self.ui.oglPath.setCoords(coords1, 1) self.ui.oglPath.setCoords(coords2, 2) if self.usepymol: self.pymolviewer.update_coords([coords1], index=1) self.pymolviewer.update_coords([coords2], index=2) print "best alignment distance", dist pass def ConnectMinima(self): self.neb = self.system.createNEB(self.ui.oglPath.coords[1], self.ui.oglPath.coords[2]) self.neb.optimize() self.nebcoords = self.neb.coords self.nebenergies = self.neb.energies self.ui.oglPath.setCoords(self.neb.coords[0,:], 1) self.ui.oglPath.setCoords(None, 2) self.ui.sliderFrame.setRange(0,self.neb.coords.shape[0]-1) if self.usepymol: self.pymolviewer.update_coords(self.nebcoords, index=1, delete_all=True) def showFrame(self, i): if hasattr(self, "nebcoords"): self.ui.oglPath.setCoords(self.nebcoords[i,:]) def show_disconnectivity_graph(self): import pylab as pl pl.ion() pl.clf() ax = pl.gca() fig = pl.gcf() graphwrapper = Graph(self.system.database) dg = DisconnectivityGraph(graphwrapper.graph, subgraph_size=2) dg.calculate() #draw minima as points xpos, minima = dg.get_minima_layout() energies = [m.energy for m in minima] points = ax.scatter(xpos, energies, picker=5) #draw line segments connecting minima line_segments = dg.line_segments for x, y in line_segments: ax.plot(x, y, 'k') #define what happens when a point is clicked on global pick_count pick_count = 0 def on_pick(event): if event.artist != points: # print "you clicked on something other than a node" return True thispoint = event.artist ind = event.ind[0] min1 = minima[ind] print "you clicked on minimum with id", min1._id, "and energy", min1.energy global pick_count #print pick_count pick_count += 1 if (pick_count % 2) == 0: self._SelectMinimum1(min1) else: self._SelectMinimum2(min1) fig = pl.gcf() cid = fig.canvas.mpl_connect('pick_event', on_pick) pl.show() def show_graph(self): import pylab as pl import networkx as nx pl.ion() pl.clf() ax = pl.gca() fig = pl.gcf() #get the graph object, eliminate nodes without edges graphwrapper = Graph(self.system.database) graph = graphwrapper.graph degree = graph.degree() nodes = [n for n, nedges in degree.items() if nedges > 0] graph = graph.subgraph(nodes) #get the layout of the nodes from networkx layout = nx.spring_layout(graph) layoutlist = layout.items() xypos = np.array([xy for n, xy in layoutlist]) #color the nodes by energy e = np.array([m.energy for m, xy in layoutlist]) #plot the nodes points = ax.scatter(xypos[:,0], xypos[:,1], picker=5, s=8**2, c=e, cmap=pl.cm.autumn) fig.colorbar(points) #label the nodes ids = [n._id for n, xy in layoutlist] for i in range(len(ids)): ax.annotate( ids[i], xypos[i] ) #plot the edges as lines for u, v in graph.edges(): line = np.array([layout[u], layout[v]]) ax.plot(line[:,0], line[:,1], '-k') #scale the axes so the points are not cutoff xmin, ymin = np.min(xypos, 0) xmax, ymax = np.max(xypos, 0) dx = (xmax - xmin)*.1 dy = (ymax - ymin)*.1 ax.set_xlim([xmin-dx, xmax+dx]) ax.set_ylim([ymin-dy, ymax+dy]) global pick_count pick_count = 0 def on_pick(event): if event.artist != points: # print "you clicked on something other than a node" return True thispoint = event.artist ind = event.ind[0] min1 = layoutlist[ind][0] print "you clicked on minimum with id", min1._id, "and energy", min1.energy global pick_count #print pick_count pick_count += 1 if (pick_count % 2) == 0: self._SelectMinimum1(min1) else: self._SelectMinimum2(min1) fig = pl.gcf() cid = fig.canvas.mpl_connect('pick_event', on_pick) #ids = dict([(n, n._id) for n in nodes]) #nx.draw(graph, labels=ids, nodelist=nodes) #ax.draw() # pl.draw() pl.show() def showEnergies(self): #note: this breaks if pylab isn't a local import. I don't know why import pylab as pl pl.ion() pl.plot(self.nebenergies, "o-", label="energies") if False: #show climbing images neb = self.neb cl=[] en=[] for i in xrange(len(neb.energies)): if(neb.isclimbing[i]): print "climbing image :", i, neb.energies[i] cl.append(i) en.append(neb.energies[i]) pl.plot(cl, en, "s", label="climbing images", markersize=10, markerfacecolor="none", markeredgewidth=2) pl.legend(loc='best') pl.show() def NewMinimum(self, minimum): E=minimum.energy minid=id(minimum) coords=minimum.coords for obj in self.listMinima: item = QMinimumInList('%.4f'%E) item.setCoords(coords) item.setMinimum(minimum) obj.addItem(item) obj.sortItems(1) def RemoveMinimum(self, minimum): minid = id(minimum) for obj in self.listMinima: itms = obj.findItems('*', QtCore.Qt.MatchWildcard) for i in itms: if(i.minid == minid): obj.takeItem(obj.row(i)) def StartBasinHopping(self): db = self.system.database self.system.database = None self.bhrunner = bhrunner.BHRunner(self.system) self.bhrunner.start() self.system.database = db def tsSearch(self): import numpy as np ts = self.system.findTS(self.ui.oglTS.coords[1]) self.transition = [ts[1][0], ts[0][0], ts[2][0]] def showFrameTS(self, i): if(self.transition): self.ui.oglTS.setCoords(self.transition[i]) def selectTransition(self): pass def delete_minimum(self): min1 = self.ui.widget.minima[1] ret = QtGui.QMessageBox.question(self, "Deleting minima", "Do you want to delete minima %d with energy %g"%(min1._id, min1.energy), QtGui.QMessageBox.Ok, QtGui.QMessageBox.Cancel) if(ret == QtGui.QMessageBox.Ok): print "deleting minima" print "deleting minimum", min1._id, min1.energy self.RemoveMinimum(min1) self.system.database.removeMinimum(min1) #this is currently not used. it may be used later though # def LocalConnect(self): # self.local_connect = self.system.create_local_connect() # # min1 = self.ui.listMinima1.selectedItems()[0].minimum # min2 = self.ui.listMinima2.selectedItems()[0].minimum # res = self.local_connect.connect(min1, min2) # ntriplets = len(res.new_transition_states) # # path = [] # for i in range(ntriplets): # tsret, m1ret, m2ret = res.new_transition_states[i] # local_path = [] # local_path.append(m1ret[0]) # local_path.append(tsret.coords) # local_path.append(m2ret[0]) # smoothpath = self.system.smooth_path(local_path) # path += list(smoothpath) # # coords = np.array(path) # self.nebcoords = coords # self.ui.oglPath.setCoords(coords[0,:], 1) # self.ui.oglPath.setCoords(None, 2) # self.ui.sliderFrame.setRange(0, coords.shape[0]-1) def doubleEndedConnect(self): return self._doubleEndedConnect(reconnect=False) def doubleEndedReConnect(self): return self._doubleEndedConnect(reconnect=True) def _doubleEndedConnect(self, reconnect=False): # min1 = self.ui.listMinima1.selectedItems()[0].minimum # min2 = self.ui.listMinima2.selectedItems()[0].minimum # min1 = self.ui. min1 = self.ui.oglPath.minima[1] min2 = self.ui.oglPath.minima[2] database = self.system.database double_ended_connect = self.system.get_double_ended_connect(min1, min2, database, fresh_connect=reconnect) double_ended_connect.connect() mints, S, energies = double_ended_connect.returnPath() clist = [m.coords for m in mints] print "done finding path, now just smoothing path. This can take a while" smoothpath = self.system.smooth_path(clist) print "done" coords = np.array(smoothpath) self.nebcoords = coords self.nebenergies = np.array(energies) self.ui.oglPath.setCoords(coords[0,:], 1) self.ui.oglPath.setCoords(None, 2) self.ui.sliderFrame.setRange(0, coords.shape[0]-1) if self.usepymol: self.pymolviewer.update_coords(self.nebcoords, index=1, delete_all=True)
class NEBExplorer(QtGui.QMainWindow): def __init__(self, parent=None, system=None, app=None): QtGui.QMainWindow.__init__(self, parent=parent) self.ui = UI() self.ui.setupUi(self) self.system = system self.app = app self.mdi = QtGui.QMdiArea(self) self.setCentralWidget(self.mdi) self.nebrunner = NEBRunner(app, system) self.nebrunner.on_update_gui.connect(self.update) self.nebrunner.on_run_started.connect(self.run_started) self.nebrunner.on_run_finished.connect(self.run_finished) # from dlg_params import EditParamsWidget # w = QtGui.QDockWidget("NEB parameters", self) # w.setWidget(EditParamsWidget(self, # self.system.params.double_ended_connect.local_connect_params.NEBparams)) # self.addDockWidget(QtCore.Qt.RightDockWidgetArea, w) # # self.editparams = w # self.energies = NEBEnergyWidget() self.view_energies = self.new_view("Energies", self.energies, QtCore.Qt.TopDockWidgetArea) self.view_distances = self.new_view("Distances", NEBDistanceWidget(), QtCore.Qt.TopDockWidgetArea) self.view_k = self.new_view("k", NEBTimeseries(attrname="k"), QtCore.Qt.BottomDockWidgetArea) self.view_nimages = self.new_view("nimages", NEBTimeseries(attrname="nimages"), QtCore.Qt.BottomDockWidgetArea) self.view_rms = self.new_view( "rms", NEBTimeseries(attrname="rms", yscale='log'), QtCore.Qt.BottomDockWidgetArea) self.show3d = Show3DWithSlider() self.view_3d = QtGui.QDockWidget("NEB parameters", self) self.view_3d.setWidget(self.show3d) self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.view_3d) #self.view_3d.setFloating(True) self.view_3d.hide() self.show3d.setSystem(self.system) self.show3d.on_frame_updated.connect(self.set_current_frame) self.centralWidget().hide() def run_started(self): self.ui.actionRun.setEnabled(False) self.ui.actionReset.setEnabled(False) self.ui.actionTS.setEnabled(False) def run_finished(self): self.ui.actionRun.setEnabled(True) self.ui.actionReset.setEnabled(True) self.ui.actionTS.setEnabled(True) def set_current_frame(self, index, sender=None): self.energies.highlight_frame(index) def new_view(self, title, widget, pos=QtCore.Qt.RightDockWidgetArea): child = QtGui.QDockWidget(title, self) child.setWidget(widget) self.addDockWidget(pos, child) self.nebrunner.on_update_gui.connect(widget.update_gui) return child def new_neb(self, coords1, coords2, path=None, run=True): self.coords1 = coords1.copy() self.coords2 = coords2.copy() self.initial_path = path self.nebrunner.run(coords1, coords2, path=path, run=run) def toggle_view(self, view, show): if show: view.show() else: view.hide() def update(self, nebrunner): self.show3d.setCoordsPath(nebrunner.path) def on_actionRun_triggered(self, checked=None): if checked is None: return self.nebrunner.continue_run() def on_actionReset_triggered(self, checked=None): if checked is None: return self.nebrunner.run(self.coords1, self.coords2, run=False, path=self.initial_path) def on_actionParams_triggered(self, checked=None): if checked is None: return if not hasattr(self, "paramsdlg"): self.paramsdlg = DlgParams(self.system.params.double_ended_connect. local_connect_params.NEBparams, parent=self) self.paramsdlg.show() def on_actionSave_triggered(self, checked=None): if checked is None: return dialog = QtGui.QFileDialog(self) dialog.setFileMode(QtGui.QFileDialog.AnyFile) dialog.selectFile("path.pickle") dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave) if (not dialog.exec_()): return filename = dialog.selectedFiles()[0] pickle.dump(self.nebrunner.path, open(filename, "w")) def on_actionLoad_triggered(self, checked=None): if checked is None: return dialog = QtGui.QFileDialog(self) dialog.setFileMode(QtGui.QFileDialog.AnyFile) dialog.setAcceptMode(QtGui.QFileDialog.AcceptOpen) if (not dialog.exec_()): return filename = dialog.selectedFiles()[0] self.initial_path = pickle.load(open(filename)) self.nebrunner.run(self.coords1, self.coords2, run=False, path=self.initial_path) def on_actionRms_toggled(self, checked): self.toggle_view(self.view_rms, checked) def on_actionE_toggled(self, checked): self.toggle_view(self.view_energies, checked) def on_actionS_toggled(self, checked): self.toggle_view(self.view_distances, checked) def on_actionK_toggled(self, checked): self.toggle_view(self.view_k, checked) def on_actionNimages_toggled(self, checked): self.toggle_view(self.view_nimages, checked) def on_action3D_toggled(self, checked): self.toggle_view(self.view_3d, checked) def on_actionTS_triggered(self, checked=None): if checked is None: return if not hasattr(self, "local_connect_explorer"): self.local_connect_explorer = ConnectExplorerDialog(self.system, self.app, parent=self) self.local_connect_explorer.show() self.local_connect_explorer.set_nebrunner(self.nebrunner)
class NormalmodeBrowser(QtGui.QMainWindow): """ the GUI for exploring normal modes """ def __init__(self, parent=None, system=None, app=None): QtGui.QMainWindow.__init__(self, parent=parent) self.ui = UI() self.ui.setupUi(self) self.ui.view3D.setSystem(system) self.system = system self._params = dict() self._params["amplitude"] = 1.0 self._params["remove_known_zeroev"] = True export = self._params["export"] = dict() export["nframes"] = 100 self._params["nframes"] = 30 self.app = app self.current_selection = None self.ui.actionShow_energies.setChecked(False) self.ui.mplwidget.hide() self.ui.actionRun.setVisible(False) def set_coords(self, coords, normalmodes=None): """ set the coordinates for which the normal modes will be computed """ self.coords = coords self.normalmodes = normalmodes if normalmodes is None: self._calculate_normalmodes() self._fill_normalmodes() self.ui.view3D.setCoords(coords) def _calculate_normalmodes(self): """ compute the normal modes """ # pot = self.system.get_potential() # E, g, hess = pot.getEnergyGradientHessian(self.coords) # metric = self.system.get_metric_tensor(self.coords) # freq, mode = normalmodes(hess, metric = metric) freq, mode = self.system.get_normalmodes(self.coords) mode = np.real(mode.transpose()) self.normalmodes = [] #self.normalmodes.append((fre[0], m.flatten())) for f, m in zip(freq, mode): self.normalmodes.append((f, m)) #np.dot(metric, m))) def _fill_normalmodes(self): """ populate the list of normal modes """ self.ui.listNormalmodes.clear() for n in self.normalmodes: self.ui.listNormalmodes.addItem(NormalmodeItem(n)) def on_listNormalmodes_currentItemChanged(self, newsel): """ change which normal mode we're looking at """ if newsel is None: self.currentmode = None return orthogopt = self.system.get_orthogonalize_to_zero_eigenvectors() mode = newsel.get_mode().copy() if self._params["remove_known_zeroev"] and orthogopt is not None: mode = orthogopt(mode, self.coords) self.currentmode = mode self.current_selection = newsel # generate the configurations from the normal mode amp = self._params["amplitude"] vector = self.currentmode nframes = self._params["nframes"] dxlist = [ amp * float(i) / nframes for i in xrange(-nframes / 2, nframes / 2) ] coordspath = [self.coords + dx * vector for dx in dxlist] coordspath = np.array(coordspath) self.dxlist = dxlist self.coordspath = coordspath self.ui.view3D.setCoordsPath(coordspath) #, labels=labels) # self.ui.view3D.ui.btn_animate.hide() if self.ui.actionShow_energies.isChecked(): self.draw_energy_plot() def draw_energy_plot(self): """ make a plot of the energies and the energies from the harmonic approximation """ if self.current_selection is None: return dxlist = self.dxlist coordspath = self.coordspath # get the energies of the configurations pot = self.system.get_potential() energies = [pot.getEnergy(coords) for coords in coordspath] # get the energies of the harmonic approximation freq = self.current_selection.get_freq() expected_energies = np.array([0.5 * (freq) * (dx)**2 for dx in dxlist]) expected_energies += pot.getEnergy(self.coords) # make the plot ax = self.ui.mplwidget.axes ax.clear() ax.plot(dxlist, energies, label="energy") ax.plot(dxlist, expected_energies, label="harmonic approximation") ax.legend(loc='best') ax.set_xlabel("displacement") self.ui.mplwidget.draw() def on_actionRun_toggled(self, checked=None): if checked is None: return if checked: self.ui.view3D.start_animation() else: self.ui.view3D.stop_animation() def on_actionShow_energies_toggled(self, checked=None): if checked is None: return if checked: self.ui.mplwidget.show() self.draw_energy_plot() else: self.ui.mplwidget.hide() def on_actionSave_triggered(self, checked=None): """ save the normal modes to disk """ if checked is None: return dialog = QtGui.QFileDialog(self) dialog.setFileMode(QtGui.QFileDialog.AnyFile) dialog.selectFile("mode.pickle") dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave) if (not dialog.exec_()): return filename = dialog.selectedFiles()[0] path = [] nframes = self._params["export"]["nframes"] for i in xrange(nframes): t = np.sin(i / float(nframes) * 2. * np.pi) path.append(self.coords + self._params["amplitude"] * t * self.currentmode) pickle.dump(path, open(filename, "w")) def on_actionParameters_triggered(self, checked=None): """ open a dialog box to change the parameters """ if checked is None: return if not hasattr(self, "_paramsdlg"): self._paramsdlg = DlgParams(self._params, parent=self) self._paramsdlg.show()