Commit abe59b48 authored by Mark Robert Johnson's avatar Mark Robert Johnson
Browse files

Merge branch 'master' of github.com:eurydyce/MDANSE

parents e5a3448a 83a72c1e
......@@ -23,7 +23,7 @@ class ControllerPanel(wx.Panel):
def build_panel(self):
self._notebook = wxaui.AuiNotebook(self)
self._notebook = wxaui.AuiNotebook(self, style=wxaui.AUI_NB_DEFAULT_STYLE & ~wxaui.AUI_NB_CLOSE_ON_ACTIVE_TAB)
self._pages = collections.OrderedDict()
self._pages["logger"] = wx.TextCtrl(self, style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_BESTWRAP|wx.HSCROLL|wx.TE_AUTO_URL)
......
......@@ -36,6 +36,7 @@ import wx.aui as wxaui
from MDANSE.Externals.pubsub import pub as Publisher
from MDANSE.App.GUI.Icons import ICONS
from MDANSE.App.GUI.Framework import has_parent
from MDANSE.App.GUI.Framework.Plugins.ComponentPlugin import ComponentPlugin
class AnimationPlugin(ComponentPlugin):
......@@ -154,7 +155,7 @@ class AnimationPlugin(ComponentPlugin):
mv = message
if not self.has_parent(mv):
if not has_parent(self,mv):
return
frame = mv.current_frame
......@@ -177,8 +178,10 @@ class AnimationPlugin(ComponentPlugin):
def on_update_animation_icon(self, message):
mv = message
if not self.has_parent(mv):
if not has_parent(self,mv):
return
if mv.animation_loop:
......@@ -187,7 +190,9 @@ class AnimationPlugin(ComponentPlugin):
self.playPause.SetBitmapLabel(ICONS["play",32,32])
def on_set_up_frame_slider(self, message):
mv = message
if not self.has_parent(mv):
if not has_parent(self,mv):
return
self.frameSlider.SetRange(0,self._parent.n_frames-1)
\ No newline at end of file
......@@ -139,12 +139,13 @@ class Query(object):
return []
try:
selection = self._parser(self.get_expression(),True)
expression = self.get_expression()
selection = self._parser.parse(expression)
except AtomSelectionParserError:
selection = ("",[])
return selection
return ("",[])
else:
return (expression,selection)
def pop(self):
return self._list.pop()
......@@ -178,7 +179,7 @@ class AtomSelectionPlugin(ComponentPlugin):
self._mainPanel = wx.Panel(self, wx.ID_ANY, size=self.GetSize())
self._notebook = wxaui.AuiNotebook(self._mainPanel, wx.ID_ANY, style=wxaui.AUI_NB_DEFAULT_STYLE^wxaui.AUI_NB_TAB_MOVE)
self._notebook = wxaui.AuiNotebook(self._mainPanel, wx.ID_ANY, style=wxaui.AUI_NB_DEFAULT_STYLE&~wxaui.AUI_NB_CLOSE_ON_ACTIVE_TAB&~wxaui.AUI_NB_TAB_MOVE)
settingsPanel = wx.Panel(self._mainPanel,wx.ID_ANY)
......@@ -321,7 +322,7 @@ class AtomSelectionPlugin(ComponentPlugin):
self._selectionSummary.AppendText("List of selected atoms:\n")
for idx in self._selection:
self._selectionSummary.AppendText("\t%s\n" % self._atoms[idx].fullName())
self._selectionSummary.AppendText("\t%s (MMTK index: %d)\n" % (self._atoms[idx].fullName(),self._atoms[idx].index))
def insert_keyword_values(self, keyword, values):
......@@ -378,7 +379,7 @@ class AtomSelectionPlugin(ComponentPlugin):
return
if not self._selectors.has_key(selectionFilter):
self._selectors[selectionFilter] = [str(v) for v in REGISTRY["selector"](selectionFilter, self._parent.trajectory.universe).choices]
self._selectors[selectionFilter] = [str(v) for v in REGISTRY["selector"][selectionFilter](self._parent.trajectory.universe).choices]
self.values.Set(self._selectors[selectionFilter])
......@@ -413,7 +414,7 @@ class AtomSelectionPlugin(ComponentPlugin):
path = os.path.basename(self.parent.trajectory.filename)
ud = REGISTRY['userdefinable']['atom_selection'](path,expression=self._expression,indexes=self._selection)
ud = REGISTRY['user_definition']['atom_selection'](path,expression=self._expression,indexes=self._selection)
UD_STORE[name] = ud
......
......@@ -82,10 +82,7 @@ class AtomTransmutationPlugin(AtomSelectionPlugin):
element = self._elements.GetStringSelection()
ud = REGISTRY['userdefinable']['atom_transmutation'](path,
expression=self._expression,
indexes=self._selection,
element=element)
ud = REGISTRY['user_definition']['atom_transmutation'](path,expression=self._expression,indexes=self._selection,element=element)
UD_STORE[name] = ud
UD_STORE.save()
......
......@@ -149,10 +149,7 @@ class AxisSelectionPlugin(ComponentPlugin):
atomNames1 = tuple([self._atomNames1.GetString(idx) for idx in atomIndexes1])
atomNames2 = tuple([self._atomNames2.GetString(idx) for idx in atomIndexes2])
ud = REGISTRY['userdefinable']['axis_selection'](path,
molecule=molName,
endpoint1=atomNames1,
endpoint2=atomNames2)
ud = REGISTRY['user_definition']['axis_selection'](path,molecule=molName,endpoint1=atomNames1,endpoint2=atomNames2)
UD_STORE[name] = ud
UD_STORE.save()
......
......@@ -157,11 +157,7 @@ class BasisSelectionPlugin(ComponentPlugin):
xAxis = tuple([self._xAxis.GetString(idx) for idx in xAxis])
yAxis = tuple([self._yAxis.GetString(idx) for idx in yAxis])
ud = REGISTRY['userdefinable']['basis_selection'](path,
molecule=molName,
origin=origin,
x_axis=xAxis,
y_axis=yAxis)
ud = REGISTRY['user_definition']['basis_selection'](path,molecule=molName,origin=origin,x_axis=xAxis,y_axis=yAxis)
UD_STORE[name] = ud
UD_STORE.save()
......
......@@ -99,9 +99,6 @@ class DataPlugin(IPlugin):
plugin.plug()
plugin.SetFocus()
def has_parent(self, window):
return False
def on_changing_pane(self, event):
......
......@@ -103,15 +103,10 @@ class JobPlugin(ComponentPlugin):
parameters = self._parametersPanel.get_value()
t = tempfile.mkstemp(prefix = "MDANSE_%s_" % self._job.type, text = True)
os.close(t[0])
self._job.save_job(t[1], parameters)
self._job.configuration.set_parameters(parameters)
self._job.configuration.configure()
script = os.path.join(PLATFORM.jobscripts_directory(),self._job._name)+'.py'
self._job.save(script, parameters)
if PLATFORM.name == "windows":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
......@@ -119,7 +114,7 @@ class JobPlugin(ComponentPlugin):
else:
startupinfo = None
subprocess.Popen([sys.executable, t[1]], startupinfo=startupinfo)
subprocess.Popen([sys.executable, script], startupinfo=startupinfo, stdin=subprocess.PIPE,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
time.sleep(1)
......@@ -145,7 +140,7 @@ class JobPlugin(ComponentPlugin):
if os.path.splitext(path)[1] != ".py":
path += ".py"
self._job.save_job(path, parameters)
self._job.save(path, parameters)
def plug(self):
......
......@@ -171,11 +171,11 @@ class QVectorsPanel(wx.Panel):
target = os.path.basename(plugin._trajectory.filename)
ud = REGISTRY['userdefinable']['q_vectors'](target,
generator=self._generator.type,
parameters=self._parameters,
q_vectors=self._grid.GetTable().data,
is_lattice=self._generator.is_lattice)
ud = REGISTRY['user_definition']['q_vectors'](target,
generator=self._generator.type,
parameters=self._parameters,
q_vectors=self._grid.GetTable().data,
is_lattice=self._generator.is_lattice)
UD_STORE[name] = ud
UD_STORE.save()
......
......@@ -33,16 +33,15 @@ Created on Apr 14, 2015
import wx
import wx.aui as wxaui
from MDANSE import UD_STORE
from MDANSE.Core.Error import Error
from MDANSE.Framework.UserDefinitions.IUserDefinition import IUserDefinition
from MDANSE.Framework.UserDefinitionsStore import UD_STORE
from MDANSE.App.GUI.Framework.Plugins.ComponentPlugin import ComponentPlugin
class UserDefinitionViewerPluginError(Error):
pass
class UserDefinitionViewerPlugin(ComponentPlugin):
type = "user_definition_viewer"
......@@ -60,7 +59,7 @@ class UserDefinitionViewerPlugin(ComponentPlugin):
self.build_plugins_tree()
def build_panel(self):
self._treePanel = wx.Panel(self, wx.ID_ANY, size=self.GetSize())
treeSizer = wx.BoxSizer(wx.VERTICAL)
......@@ -102,22 +101,19 @@ class UserDefinitionViewerPlugin(ComponentPlugin):
def set_plugins_tree(self, node, data):
for k, v in data.items():
dataItem = wx.TreeItemData(v)
subnode = self._tree.AppendItem(node, str(k), data=dataItem)
if isinstance(v, IUserDefinition):
dataItem = wx.TreeItemData(v)
subnode = self._tree.AppendItem(node, str(k), data=dataItem)
self.set_plugins_tree(subnode, v)
self._tree.SetItemTextColour(subnode, 'red')
elif isinstance(v, dict):
dataItem = wx.TreeItemData(v)
subnode = self._tree.AppendItem(node, str(k), data=dataItem)
self.set_plugins_tree(subnode, v)
self._tree.SetItemTextColour(subnode, 'blue')
else:
dataItem = wx.TreeItemData(v)
subnode = self._tree.AppendItem(node, str(k), data=dataItem)
self._tree.SetItemTextColour(subnode, 'green')
def on_show_info(self, event):
......
......@@ -35,7 +35,6 @@ import abc
import wx
from MDANSE import REGISTRY
from MDANSE.App.GUI.Framework.Plugins.IPlugin import IPlugin, plugin_parent
class IWidget(wx.Panel):
......@@ -89,16 +88,6 @@ class IWidget(wx.Panel):
def add_widgets(self):
pass
def has_parent(self, target):
if self == target:
return True
if self.TopLevelParent == self:
return False
return self.has_parent(self.Parent, target)
def build_panel(self):
self._staticBox = wx.StaticBox(self, wx.ID_ANY, label=self.label)
......
......@@ -38,6 +38,7 @@ from MDANSE.Externals.pubsub import pub
from MDANSE.Framework.Configurable import ConfigurationError
from MDANSE.App.GUI import DATA_CONTROLLER
from MDANSE.App.GUI.Framework import has_parent
from MDANSE.App.GUI.Framework.Widgets.IWidget import IWidget
class MMTKTrajectoryWidget(IWidget):
......@@ -71,7 +72,7 @@ class MMTKTrajectoryWidget(IWidget):
window, filename = message
if not self.has_parent(window):
if not has_parent(self,window):
return
data = DATA_CONTROLLER[filename].data
......
......@@ -38,6 +38,7 @@ from MDANSE.Externals.pubsub import pub
from MDANSE.Framework.Configurable import ConfigurationError
from MDANSE.App.GUI import DATA_CONTROLLER
from MDANSE.App.GUI.Framework import has_parent
from MDANSE.App.GUI.Framework.Widgets.IWidget import IWidget
class NetCDFInputWidget(IWidget):
......@@ -77,7 +78,7 @@ class NetCDFInputWidget(IWidget):
window, filename = message
if not self.has_parent(window):
if not has_parent(self,window):
return
self._netcdf = DATA_CONTROLLER[filename].netcdf
......
def has_parent(window, target):
if window == target:
return True
else:
return has_parent(window.Parent, target)
......@@ -27,7 +27,7 @@
'''
Created on Apr 10, 2015
@author: pellegrini
@author: Gael Goret and Eric C. Pellegrini
'''
import collections
......@@ -46,10 +46,10 @@ from MDANSE.Core.Singleton import Singleton
from MDANSE.Framework.Status import convert_duration, total_seconds
from MDANSE.Framework.Jobs.JobStatus import JobState
from MDANSE.Externals.pubsub import pub
from MDANSE.Logging.Logger import LOGGER
from MDANSE.App.GUI.Icons import ICONS
from MDANSE.App.GUI.Events.JobControllerEvent import EVT_JOB_CONTROLLER, JobControllerEvent
from MDANSE.App.GUI.LogfileFrame import LogfileFrame
class JobController(threading.Thread):
......@@ -65,6 +65,8 @@ class JobController(threading.Thread):
self._registry = collections.OrderedDict()
self._firstCheck = True
if start:
self.start()
......@@ -73,12 +75,29 @@ class JobController(threading.Thread):
return self._registry
def remove_job(self, job):
def kill_job(self, job):
if not self._registry.has_key(job):
return
if self._registry[job]['state'] == 'running':
try:
PLATFORM.kill_process(self._registry[job]['pid'])
except:
return
if os.path.exists(self._registry[job]['temporary_file']):
try:
os.unlink(self._registry[job]['temporary_file'])
except:
return
try:
del self._registry[job]
except KeyError:
pass
return
self.update()
def run(self):
......@@ -96,11 +115,11 @@ class JobController(threading.Thread):
# The list of the registered jobs.
jobs = [f for f in glob.glob(os.path.join(PLATFORM.temporary_files_directory(),'*'))]
# Loop over the job registered at the previous controller check point
for j in self._registry.keys():
for j in self._registry.keys():
# Case where a job has finished during two controller check points (i.e. its temporary file has been deleted)
if self._registry[j]['state'] == 'finished':
continue
......@@ -130,6 +149,8 @@ class JobController(threading.Thread):
if not isinstance(info,JobState):
continue
name = info['name']
# Check that the pid of the running job corresponds to an active pid.
running = (info['pid'] in pids)
......@@ -139,15 +160,14 @@ class JobController(threading.Thread):
jobStartingTime = datetime.datetime.strptime(info["start"],"%d-%m-%Y %H:%M:%S")
procStartingTime = datetime.datetime.strptime(pids[info['pid']],"%d-%m-%Y %H:%M:%S")
running = (jobStartingTime >= procStartingTime)
# Case where the job is running, update the registry with the new status
if running:
self._registry[j] = info
self._registry[name] = info
# Case where the job is not running
else:
info['state'] = 'aborted'
self._registry[j] = info
self._registry[name] = info
wx.PostEvent(self._window, JobControllerEvent(self._registry))
......@@ -165,14 +185,16 @@ class JobControllerPanel(wx.ScrolledWindow):
self._jobs = collections.OrderedDict()
self.build_panel()
self._gbSizer = wx.GridBagSizer(0,0)
self.SetSizer(self._gbSizer)
self._jobsController = JobController(self,True)
EVT_JOB_CONTROLLER(self,self.on_update)
pub.subscribe(self.on_start_job,"on_start_job")
self._jobsController = JobController(self,True)
def __del__(self):
self._jobsController.stop()
......@@ -182,22 +204,21 @@ class JobControllerPanel(wx.ScrolledWindow):
def on_start_job(self,message):
self._jobsController.update()
def add_job(self, name, jobStatus):
r = self._gbSizer.Rows
self._jobs[name] = r
name = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL)
pid = intctrl.IntCtrl(self, wx.ID_ANY, style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL)
start = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL)
elapsed = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL)
state = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL)
name = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL,value=jobStatus['name'])
pid = intctrl.IntCtrl(self, wx.ID_ANY, style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL,value=jobStatus['pid'])
start = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL,value=jobStatus['start'])
elapsed = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL,value=jobStatus['elapsed'])
state = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL,value=jobStatus['state'])
progress = wx.Gauge(self, wx.ID_ANY,range=100)
eta = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL)
progress.SetValue(jobStatus['progress'])
eta = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL,value=jobStatus['eta'])
kill = wx.BitmapButton(self, wx.ID_ANY, ICONS["stop",24,24])
r = self._gbSizer.GetRows()
self._gbSizer.Add(name ,pos=(r,0),flag=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL)
self._gbSizer.Add(pid ,pos=(r,1),flag=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL)
self._gbSizer.Add(start ,pos=(r,2),flag=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL)
......@@ -206,73 +227,47 @@ class JobControllerPanel(wx.ScrolledWindow):
self._gbSizer.Add(progress,pos=(r,5),flag=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL)
self._gbSizer.Add(eta ,pos=(r,6),flag=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL)
self._gbSizer.Add(kill ,pos=(r,7),flag=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL)
name.Bind(wx.EVT_LEFT_DCLICK,self.on_display_logfile)
self._gbSizer.Layout()
kill.Bind(wx.EVT_BUTTON, self.on_kill_job)
def build_panel(self):
self._gbSizer = wx.GridBagSizer(0,0)
for i,(col,s) in enumerate(self.columns):
self._gbSizer.Add(wx.TextCtrl(self,wx.ID_ANY,value=col.upper(),size=s,style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL),pos=(0,i),flag=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL)
self._gbSizer.AddGrowableCol(5)
self.SetSizer(self._gbSizer)
def on_display_logfile(self,event):
row = self._gbSizer.GetItemPosition(event.GetEventObject())[0]
name = self._gbSizer.FindItemAtPosition((row,0)).Window.GetValue()
f = LogfileFrame(self,name)
f.Show()
def on_kill_job(self, event):
row = self._gbSizer.GetItemPosition(event.GetEventObject())[0]
state = self._gbSizer.FindItemAtPosition((row,4)).Window.GetValue()
if state == "finished":
return
for row in range(self._gbSizer.GetCols()):
name = self._gbSizer.FindItemAtPosition((row,0)).Window.GetValue()
name = self._gbSizer.FindItemAtPosition((row,0)).Window.GetValue()
d = wx.MessageDialog(None, 'Do you really want to kill job %r ?' % name, 'Question', wx.YES_NO|wx.YES_DEFAULT|wx.ICON_EXCLAMATION)
if d.ShowModal() == wx.ID_YES:
try:
pid = self._gbSizer.FindItemAtPosition((row,1)).Window.GetValue()
PLATFORM.kill_process(pid)
except Exception:
LOGGER("The job %r could not be killed." % name,"error")
else:
event.GetEventObject().Disable()
def update_job(self,name,jobStatus):
r = self._jobs[name]
for i,(name,_) in enumerate(self.columns):
try:
self._gbSizer.FindItemAtPosition((r,i)).Window.SetValue(jobStatus[name])
if jobStatus['state'] == 'finished':
self._gbSizer.FindItemAtPosition((r,7)).Window.Disable()
except AttributeError:
pass
info = "\n".join(["%s = %s" % (k,v) for k,v in jobStatus.items()])
self._gbSizer.FindItemAtPosition((r,0)).Window.SetToolTipString(info)
self._jobsController.kill_job(name)
def on_update(self, event):
registry = event.registry
for name,jobStatus in registry.items():
if not self._jobs.has_key(name):
if jobStatus["state"] == "aborted":
continue
self.add_job(name,jobStatus)
self.update_job(name,jobStatus)
self._gbSizer.Clear(True)
for i,(col,s) in enumerate(self.columns):
self._gbSizer.Add(wx.TextCtrl(self,wx.ID_ANY,value=col.upper(),size=s,style=wx.TE_READONLY|wx.ALIGN_CENTER_HORIZONTAL),pos=(0,i),flag=wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL)
self._gbSizer.AddGrowableCol(5)
self._gbSizer.Layout()
for name,jobStatus in registry.items():
self.add_job(name,jobStatus)
if __name__ == "__main__":
app = wx.App(0)
......