User:SreenathaB

From ASCEND
Jump to navigation Jump to search

I am a Computer Science and Engineering student at "International Institute of Information Technology, Hyderabad"(IIITH) interested in GUI development for applications. Currently, I am involved in developing the PyGTK GUI of ASCEND.

Subversion account : sreenatha:

GSoC 2012 project : GUI Improvements and Bug Squashing

The original proposal is on the GSoC-melange website.

The objectives of this project are

  • Develop the Integrator window
  • Add additional features to the PyGTK GUI
    • Improve IPython console support to the PyGTK GUI
    • Implement the "incidence graph" functionality in windows
  • Enable Loading/Saving changed models
  • Port the DISPLAY equivalent of the Tcl/Tk GUI to PyGTK GUI
  • Add an exit prompt dialog box to the PyGTK GUI
  • Bug fixing
  • Add a sub menu for selecting display options to the "Diagnose" window

Exit Dialog

  • Patched up gtkbrowser.py to ensure that once a delete-event occurs(by clicking on the exit button on title bar), an exit pop-up fires up and asks the user to confirm his exit from the main window i.e, ASCEND browser.
  • Used gtk.MessageDialog instead of gtk.Dialog because according to the docs at pygtk.org, gtk.MessageDialog saves a bit of time when used for trivial purposes(displaying an exit pop-up in this case).
  • Ensured that the function do_quit() is called to perform the clean up procedures before exiting.
  • Here is the link to the patch http://code.ascend4.org/viewvc/code/branches/sreenatha/pygtk/gtkbrowser.py?r1=4124&r2=4165&view=patch
  • Here is an image of the exit pop-up

Plot functionality

  • Set the TreeSelection mode of the gtk.TreeView object 'treeview2'(represents Y-axis) in 'PlotDialog' class to gtk.SELECTION_MULTIPLE. The user can now select multiple items from the Y-axis column.
  • Used 'get_selected_rows' method instead of 'get_selection' to obtain the selected items of the treeview object because the later was giving errors when the mode of the TreeSelection is set to gtk.SELECTION_MULTIPLE
  • Changed the type of self.ycol in 'PlotDialog' class from ObserverColumn to list inorder to account for the multiple columns selected for plotting
  • Added a for loop to check if any of the items in the list selected for plotting against Y-axis is the same as the item selected for plotting against X-axis.
  • Modified 'plot' function to display the plots of all the items in the list, y, passed as argument. Unfortunately, all the plot figures occur at the same location.
  • Current version of observer.py pygtk/observer.py
  • Selecting three columns for plot in the dyn_tank.a4c
  • Plots for the above selection'
  • Improved the plotting functionality by restricting the number of figures that can be drawn to one(plots may be multiple)
    • If number of plots is 2, the y-axis is provided with two scales(corresponding to the two plots). The two plots are drawn using different styles and can be identified using the legend displayed at the top left and right corners of the graph.


    • If number of plots is not 2, the graph has several divisions of plots each of which has a y-axis of it's own. The x-axis is common for all the plots, however. All the y axes are scaled to the same amount.
  • As John suggested, grouped the legends towards the upper left corner and made them transparent. Not using the default lineplot of matplotlib because it generates incorrect, non existing data.

Integrator Window

  • Added 'indepvar' as a member to the class 'IntegratorWindow' to hold a reference to the independent variable in the simulation. This indepvar is a ascpy.Variable instance which is accessible by any of IntegratorWindow's methods.
  • Removed the following line due to inappropriate assumption about the independent variable of the model/simulation.
_t = self.integrator.getCurrentTime( )
  • Used the following two lines of code instead
_u = self.indepvar.getInstance().getType().getPreferredUnits()
_t = str(self.indepvar.getInstance().getRealValue() / _u.getConversion()) 
  • Added 'indepvar' as a variable-member of the IntegratorWindow and couldn't generate it, on the fly, for two reasons.
    1. The parse_entry function, which has been reused from properties.py, needs the entry's instance in ascpy.Instance format. This instance, in proper format, can be derived from the indepvar 'Variable'. However, this 'Variable' can't be passed to parse_entry due to some weird errors regarding the number of arguments being passed.
    2. Most of the methods within the IntegratorWindow use the 'indepvar' variable directly or indirectly(for preferred units and stuff). So, argument passing overhead can be required by making it accessible to all these methods.
  • Added 'parse_entry' as the callback function for 'changed' signal(inherited from gtk.Editable) for the gtk.Entry widgets corresponding to those parameters which have units(Start,Duration,Initial substep, Minimum substep, Maximum substep). Also added the 'taint_entry' method which actually colors the input box depending on the entry. See Image below.
  • Found out that 'color_entry' method is actually needed because unlike the properties window, which has the same type of widgets for the inputs, the integrator window has different kinds of widgets(gtk.ComboBox) for receiving the data from the user. So, color_entry is called for these entries which donot contain the 'set_property' method used to set the secondary-icon's properties.
  • Realized that it is better to set the value and units of the parameters once(when the start button is clicked)rather than many(whenever the entries are changed). In other words, it is betterif the following code is present in 'check_inputs' method(which is called from the 'run' method to check the inputs before running the integrator engine) than the 'parse_entry' method.
 _val = {}
 units = ''
 for _k,_v in {
        self.beginentry:[lambda x:float(x),"begin"]
        , self.durationentry:[lambda x:float(x),"duration"]
        , self.nstepsentry:[lambda x:int(x),"num"]
 }.iteritems():
         x = RealAtomEntry(self.indepvar.getInstance(), _k.get_text())
         x.checkEntry()
         if _k == self.beginentry: 
                 units = x.units
                 #self.indepvar.getInstance().setRealValueWithUnits()
         if _k == self.nstepsentry:
                 _val[_v[1]] = _v[0](_k.get_text())
         else :
                 _val[_v[1]]=_v[0](x.getValue()/ascpy.Units(units).getConversion())
    
         self.integrator.setLinearTimesteps(ascpy.Units(units), _val["begin"], (_val["begin"]+_val["duration"]), _val["num"])
  • By instantiating the Preferences class, one can get the preferred units of any type by giving as argument, the var type in string format. However, there is a problem with this approach in case of the integrator window. The type of the independent variable in a model/simulation is not known before hand. So, I used a different approach. Here is what I did
    • Used the 'getIndependentVariable' method of the integrator instance(self.integrator) to get a 'Variable' class instance(self.indepvar)
    • Every member of this 'Variable' class has a method called 'getInstance' which returns an ascpy.Instance object
    • From this return value, the var type can be found using the instance's 'getType' method
    • Once the type of the variable has been found, there seem to be two ways of getting the preferred units for it.(Fortunately, every solver_var of a similar type in the simulation has to have the same preferred units). I used the second method.
      1. Use that var type(string) as an argument to getPreferredUnits method of 'Preferences' class-instance which can be generated on the fly.
      2. Use the method 'getPreferredUnits' of the 'Type' class instance y.getInstance().getType()
  • Patch to the original integrator.py http://code.ascend4.org/viewvc/code/branches/sreenatha/pygtk/integrator.py?r1=4124&r2=4237&view=patch
  • Patch to the glade file ascend.glade http://code.ascend4.org/viewvc/code/branches/sreenatha/pygtk/glade/ascend.glade?r1=4209&r2=4243&view=patch. Please note that this patch has to be applied to the glade file present at the directory pointed by the environment variable INSTALL_ASCDATA which the user can set through the terminal.
  • Removed 'label16' in the integrator tab that says 'To add columns, right-click variables in Simulation Tab'

Diagnose Window

  • Bug 273
    • Changed the 'diagnosewin' entry in the glade file(ascend.glade) to accommodate for the additional functionality of showing the units of the variables in the variable entry box in the diagnose window, var_popup and rel_popup.
    • Screenshots of ascend running on models/johnpye/pendulum.a4c
      • Units of measurement added for the 'varval' gtkButton in the Diagnose blocks window
      • Units of measurement added for the Variable pop-up
      • Units of measurement added for the Relation pop-up
      • The popup displays the units of measurement for each of the variables that the relation is incident with
  • Added, as proposed, a sub-menu for selecting display options similar to the Solver Reporter pop-up. The sub-menu has the following menu items
    • Show Window
    • Close on Converged
    • Close on non-converged
  • Replaced 'on_diagnose_blocks_click' in gtkbrowser.py with the following callbacks
    • on_diagnose_show_window_toggle
    • on_diagnose_close_on_converged_toggle
    • on_diagnose_close_on_nonconverged_toggle
  • Modified files
  • Removed these options and reverted to the old style of using the diagnose window as a tool
  • Added "Show Block Diagnosis" button to the Solver reporter window so that when a model is solved, the user can view the Diagnose Blocks window in a more intutive manner.
  • Added a check button to the diagnose window, as suggested by john, so that the user can choose to have either the default units or the preferred units of the variable displayed(in the variable and relation popups as well).
  • The units(if any) displayed in the diagnose window entries will change dynamically when the check box is clicked/unclicked.
  • The following code illustrates how the units of the variable 'var' are found depending on the state of the checkbox
units = ''     
default_units = var.getInstance().getType().getDimensions().getDefaultUnits().getName().toString()
pref_units = var.getInstance().getType().getPreferredUnits().getName().toString()
if checkbox==set:
  if pref_units:
    units = pref_units
else:
  if default_units!='?':
    units = default_units
  • Screenshot of the diagnose window checkbox

View Window

  • Added view items in the GtkMenuItem with id='filemenu_menu' and the GtkToolbar with id='toolbar3' using the Glade Interface Designer for linux
  • Defined callback function 'view_click' in gtkbrowser.py for these added items
  • Replicated from 'open_click', the code for displaying the window to choose/select the location of the model, in view_click
  • Added a class 'ViewModel' to gtkbrowser.py(changed to modelview.py to enable viewing the models in the 'Models' tab) which defines the view window that displays the actual content of the model selected
    • Implementation details
      • gtk.Window for the view window
      • gtk.VBox for the vertical box inside the window
      • gtk.TextView for the viewing widget
      • gtk.ScrolledWindow for the scrollable window
      • The view window contains the vertical box container inside which is a scrollable window encapsulating the widget(gtk.TextView) that actually shows the content of the file. Because TextView widget doesn't have scroll-down/up options, it is placed in a scrollable window.
  • The user has to select a file using a gtk.FileChooserDialog widget before viewing the model.
  • Added tooltips for the menu items of the filemenu(to which the view menu item has been added).
  • Image of the view window
  • Image of the glade interface designer used to edit ascend.glade
  • Enabled syntax highlighting for the View window(Referred to canvasproperties.py)
  • Updated moduleview.py to support rightclicks on the models and modules in Modules tab
  • Upon rightclick on a model of the module or even the module itself, a menu with only one option(View) is displayed. Clicking this menuitem will send a signal to the callback function view_activate which will instantiate the ViewModel class(which defines the View Window that pops up).
  • Also added support for viewing ATOM declarations and DEFINITIONs

Bug 558 and Integrator error

  • Fix for bug 558 present in gtkbrowser.py at http://code.ascend4.org/viewvc/code/branches/sreenatha/pygtk/gtkbrowser.py?view=markup
  • Screenshot of the output when the command $./ascend ../models/johnpye was run
  • It is possible to stop the modules/GUI (that are responsible for option parsing) from loading in the specific case of a single incorrect command line argument. However, if we generalize it to the case of any number of arguments, no option parsing would be done. Without option parsing, we can't be sure whether the given path is an incorrect file address or a correct assets-directory address.
  • Reduced the overhead of loading the GUI components of the Integrator window from the glade file in the case where there is no independent variable in the model. So, if integration is not possible(i.e, if independent variable is not found in the model), only an error dialog will pop up(when the user clicks on the integrate button) while previously the integrator window got loaded before the error dialog.
    • Before
    • After