Index: sc/tools/event_selection/installer/EventSelection.py
===================================================================
--- /misc/tools/event_selection/installer/EventSelection.py	(revision 6300)
+++ 	(revision )
@@ -1,1104 +1,0 @@
-#!/usr/bin/env python
-################################################################################
-# Earthquake Event Selection.
-################################################################################
-
-import os
-import os.path
-import sys
-import re
-import glob
-import shutil
-import time
-import tempfile
-try:
-    import cpickle
-except:
-    import pickle
-
-##if __name__ == '__main__':
-try:
-    import wx
-except ImportError:
-    print 'Sorry, you have to install WxPython.'
-    print 'Get it from: [http://www.wxpython.org/download.php#binaries].'
-    sys.exit(1)
-Imported_PyEmbeddedImage = True
-try:
-    from wx.lib.embeddedimage import PyEmbeddedImage
-except ImportError:
-    Imported_PyEmbeddedImage = False
-
-#from wx.lib.mixins.listctrl import ColumnSorterMixin
-
-
-######
-# Various constants
-######
-
-# where the data lives
-if sys.platform == 'win32':
-    BaseDirectory = r'N:\georisk_models\tsunami\models\PTHA'
-else:
-    BaseDirectory = '/nas/gemd/georisk_models/tsunami/models/PTHA'
-
-# name of the fault name file (in multimux directory)
-FaultNameFilename = 'fault_list.txt'
-
-# program name and version
-APP_NAME = 'EventSelection'
-APP_VERSION = '0.6'
-
-# name of the configuration filename
-# GUI values are saved in this file for next time
-ConfigFilename = 'EventSelection.cfg'
-
-# name of the 'fault XY' output file
-FaultXYFilename = 'fault.xy'
-
-# name of the quake probability output file
-QuakeProbFilename = 'quake_prob.txt'
-
-# name of the output URS data module
-# note: the %d is where the event number goes
-URSDataFilename = 'urs_data_%6.6d.py'
-
-# name of the output bash params file
-# note: the %d is where the event number goes
-GridBashScriptName = 'faults_%6.6d.params'
-
-# map display name to directory name
-Regions = [ ('Australia',  'Australia'),
-            ('India',      'Indian'),
-            ('SW Pacific', 'SW_Pacific')
-          ]
-
-# pattern string used to split multimax data
-SpacesPatternString = ' +'
-
-# generate 're' pattern for 'any number of spaces'
-SpacesPattern = re.compile(SpacesPatternString)
-
-# Global holding current results sub-directory
-ResultSubdir = ''
-
-# a small value to perturb the user limits
-Epsilon = 1.0E-6
-
-# GUI definitions
-BOX_WIDTH = 400
-BOX_HEIGHT = 360
-BOX2_HEIGHT = 285
-
-
-FORM_WIDTH = BOX_WIDTH + 15
-FORM_HEIGHT = 755
-
-START_YOFFSET = 7
-OUT_TEXT_XOFFSET = 8
-OUT_TEXT_YOFFSET = 11
-OUTPUT_BOX_HEIGHT = 45
-
-GEN_YOFFSET = 15
-GEN_DELTAY = 25
-GEN_LABELXOFFSET = 5
-GEN_TEXTXOFFSET = BOX_WIDTH/2 + GEN_LABELXOFFSET + 10
-
-TEXTLIST_WIDTH = BOX_WIDTH - 10
-TEXTLIST_HEIGHT = 200
-
-CTL_WIDTH = BOX_WIDTH / 2
-CTL_HEIGHT = 22
-
-BUTTON_WIDTH = 100
-BUTTON_HEIGHT = 30
-
-DOUBLE_BUTTON_OFFSET = 8
-
-COMBO_FUDGE = 2
-
-# Copies of various parameters
-Region = ''
-GaugeNumber = ''
-MinimumHeight = ''
-MaximumHeight = ''
-
-
-################################################################################
-# This code was generated by img2py.py
-# Embed the ICON image here, so we don't need an external *.ico file.
-# Icon image inspired by Hokusai's print "The Great Wave off Kanagawa"
-# (Kanagawa oki nami ura) from the "Thirty-Six Views of Mount Fuji" series.
-# http://commons.wikimedia.org/wiki/Image:The_Great_Wave_off_Kanagawa.jpg
-################################################################################
-
-if Imported_PyEmbeddedImage:
-    def getIcon():
-        return PyEmbeddedImage(
-          "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAABDBJ"
-          "REFUWIXtlmtsFFUUx393dnbbbh+hlPQVKEEBKSLyEEEhqFQSNYAQNahAIJJUidEEtUQIRgk+"
-          "GkSMJBJjUEADCVghtipSjeWhWIoh5VXoBqgU2aWvLbt0H52dmesH6La1U7OVbvCD59PcmTPn"
-          "/M69/3vuFYDkFppyK5P/D/CfAFD//kIgcGbkkpk/GYczjat/umiqrUIaBgA2RwKG1h71lxZP"
-          "/xJAkJiazn3LNnD7g8+gqI5o0Iaawxza+CJ3zlnGiIKF+C6f5+iWVTicaaRkDSXY4uHCwa/Q"
-          "20N9BhGAdA7IIjVnGNNf3Uz60NEghYWr7PJLz3GguZ6Tuz/C8/teQoFrDBoxEefAbPyeOtzV"
-          "FZhGxBpg9voDMnvMVIRi6xN57xVJJF0LkDScreSHVbNob/P28Fdyxk7vt+TX0wmuz46k/si3"
-          "uMq3kTVqCmPmvWTp30OE/WWu8q1UbV5J2N9C7rgZvS5BXACklFTveI9BIycweNKj1FeWcWrP"
-          "RojOTqfdVB8QvSheILEnp6EF/OgBPwNvG8v8LS6e3lrLhAWrUZTOukVhuYzLYSRNo4u2ZLfi"
-          "qza/zvFd7yOR8euEXZNfOFjCzsV3sOu5fLwXTzP84UXRuYt7K24+d4yK4oUEvW600DXqDpTQ"
-          "1ngxulHjtgs67OLhUgxDx56cxl1zX0ZKk0MbCqPf46aBDpPSIBJqI3y1Gb/7HJ4T+6nd+xlB"
-          "X1NXAAlYtV/LkN18TSNCqLUR58DsmBtaqNXD9ysfwVt3skMDsSa/7msaEa6c/pWg14PeHmTn"
-          "khGUvTKda1cuWAI3nj3CH7/soaHmNwy9naT0bKYUrgdE7yIUwmplJH73OUqXT+OnNU9wfNc6"
-          "bPZEFNVO45lKKtYtBiRhfzOGFqZj39WUbuLHtU9SunwquwvHEWhxkzF8AopN7R1AWpyIquZn"
-          "3xuz8F2qZdKSNeTdM5MzO9/BnpBE7riHULU2VAWqd7zL1y+Mp7W+BhDcPX8FAsHo2cuItAcJ"
-          "eT00uaqQht43Edbu+5wDHyzt8T5j2BimLV2Lt+EyWijAsS/ewjQN0vPymfvxUYRQ2P7sEOyJ"
-          "yeTPep6w30tN2Sa0gK9v2/D8z9u7z4iqous6LXWn+Gb1PBwOB5qmkZiaQcGKbZS/+Tju6goG"
-          "T5yJPSkV32UXlZ8WdYsRcyMSSPRQoHMsBKZpdvPRNA2AlMwhaG1eMkdNJiUrj5CviUDTJcu4"
-          "MQNIIDlraOdYyh4AHdZSd4JIOMhjxfsAyf7iRTdEaVFYrBqwKZLqkg+p/OQ1ZAz3PiEENjUB"
-          "U9cwpTUogBLrJVJKGD3jKewJSTH6S/RI+B+T3wCIrQmZUmAbMJh7F6xAtfXfEdLH01Awcl4R"
-          "eeMfwOFw3AoAUBOc3F/0JZnDx5OUFNty9CsAgDM9h4K3vyNvyhxSUlJvCuAvPDCzruPdn6UA"
-          "AAAASUVORK5CYII=")
-
-
-##################################################################################
-### A class to create a sorted listctrl mixin.
-### From: http://www.zetcode.com/wxpython/advanced/.
-##################################################################################
-##
-##class SortedListCtrl(wx.ListCtrl, ColumnSorterMixin):
-##    def __init__(self, parent, *args, **kwargs):
-##        wx.ListCtrl.__init__(self, parent, *args, **kwargs)
-##        ColumnSorterMixin.__init__(self, 10)
-##        self.itemDataMap = None
-##
-##    def GetListCtrl(self):
-##        return self
-    
-################################################################################
-# An object that behaves like a dictionary but is pickled/unpickled from a file.
-################################################################################
-
-class Config(object):
-    """
-    An object that behaves like a dictionary but is persistent:
-
-        cfg = Config('filename')
-        cfg['save'] = 'A saved value'
-        cfg[123] = 'value 123'
-        print cfg['save']
-
-    The values stored in the file 'filename' will be available to any
-    application using that config file.
-    """
-
-    def __init__(self, configfile=None):
-        """
-        __init__(self, String filename=None) -> Config
-        """
-
-        self.delconf = False
-        self.cfgdict = {}
-        self.changed = False
-        if not configfile:
-            self.delconf = True
-            configfile =tempfile.mktemp()
-        self.configfile = os.path.abspath(configfile)
-        if os.path.exists(self.configfile):
-            try:
-                f = open(configfile, "r")
-                u = pickle.Unpickler(f)
-                self.cfgdict = u.load()
-            except pickle.UnpicklingError, e:
-                print e
-            except:
-                pass
-            else:
-                f.close()
-
-    def __setitem__(self, key, value):
-        """
-        Override to allow: cfg[<key>] = <value>
-        """
-        self.cfgdict[key] = value
-        self.changed = True
-
-    def __getitem__(self, key):
-        """
-        Override to allow: <var> = cfg[<key>]
-        """
-        return self.cfgdict.get(key, None)
-
-    def __str__(self):
-        """
-        __str__(self) -> String
-        """
-        return "<config object at %s>" % hex(id(self))
-
-    def getfilename(self):
-        """
-        getfilename(self) -> String filename
-        """
-        return self.configfile
-
-    def setdeleted(self):
-        """
-        setdeleted(self)
-        """
-        self.delconf = True
-
-    def save(self):
-        """
-        save(self)
-        """
-        try:
-            f = open(self.configfile, "w")
-            p = pickle.Pickler(f)
-            p.dump(self.cfgdict)
-        except pickle.PicklingError, e:
-            print e
-        else:
-            f.close()
-        self.changed = False
-
-    def close(self):
-        """
-        close(self)
-        """
-        if self.changed:
-            self.save()
-        if self.delconf:
-            if os.path.exists(self.configfile):
-                os.remove(self.configfile)
-
-    def __del__(self):
-        """
-        __del__(self)
-        """
-        self.close()
-
-################################################################################
-# This code implements the logic of David Burbidge's 'list_quakes' program.
-# Except the two output files are now in CSV format.
-#################################################################################
-
-##
-# @brief Function to do all the work - list the quakes selected.
-def list_quakes(event_num, min_height, max_height, InvallFilename,
-                TStarFilename, FaultXYFilename, QuakeProbFilename):
-    ##
-    # @brief Class to hold i_invall data
-    class Inval(object):
-        def __init__(self, lon, lat):
-            self.lon = lon
-            self.lat = lat
-
-        def __str__(self):
-            return '.lon=%g, .lat=%g' % (self.lon, self.lat)
-
-
-    ##
-    # @brief Class to hold T-**** data
-    class TStar(object):
-        def __init__(self, ipt, zquake, zprob, mag, slip, ng, ng_data):
-            self.ipt = ipt
-            self.zquake = zquake
-            self.zprob = zprob
-            self.mag = mag
-            self.slip = slip
-            self.ng_data = [int(i) for i in SpacesPattern.split(ng_data)]
-            if len(self.ng_data) != ng:
-                raise RuntimeError(1, "Error parsing T-***** data: %s" % msg)
-
-        def __str__(self):
-            return ('.ipt=%d, .zquake=%g, .zprob=%g, .mag=%g, .slip=%g, .ng_data=%s' %
-                    (self.ipt, self.zquake, self.zprob, self.mag,
-                     self.slip, str(self.ng_data)))
-
-
-    # read i_invall file
-    try:
-        fd = open(InvallFilename, "r")
-        invall_lines = fd.readlines()
-        fd.close()
-    except IOError, msg:
-        raise RuntimeError(1, "Error reading file '%s': %s" % 
-                           (InvallFilename, msg))
-
-    # trash the first three lines
-    invall_lines = invall_lines[3:]
-
-    # split i_invall data into fields
-    invall_data = []
-    for line in invall_lines:
-        l = line.strip()
-        (lon, lat, _) = SpacesPattern.split(l, maxsplit=2)
-        invall_data.append(Inval(float(lon), float(lat)))
-
-    del invall_lines
-
-    # now read T-**** file, creating filename from event #
-    try:
-        fd = open(TStarFilename, "r")
-        tstar_lines = fd.readlines()
-        fd.close()
-    except IOError, msg:
-        raise RuntimeError(1, "Error reading file: %s" % msg)
-
-    # trash the first line of T-**** data
-    tstar_lines = tstar_lines[1:]
-
-    # get the data from tstar_lines
-    tstar_data = []
-    min_wave = min_height - Epsilon
-    max_wave = max_height + Epsilon
-    for (ipt, line) in enumerate(tstar_lines):
-        l = line.strip()
-        (zquake, zprob, mag, slip, ng, ng_data) = SpacesPattern.split(l, maxsplit=5)
-        zquake = float(zquake)
-        zprob = float(zprob)
-        mag = float(mag)
-        slip = float(slip)
-        ng = int(ng)
-        ng_data = ng_data.strip()
-        # only remember the data if zquake in wave height range and zprob > 0.0
-        if zprob > 0.0 and (min_wave <= zquake <= max_wave):
-            tstar_data.append(TStar(ipt+1, zquake, zprob, mag, slip, ng, ng_data))
-    del tstar_lines
-
-    # write out lines joining centroids
-    try:
-        outfd = open(FaultXYFilename, "w")
-    except IOError, msg:
-        raise RuntimeError(1, "Error opening output file: %s" % msg)
-
-#    outfd.write('     Lon      Lat    Quake_ID  Subfault_ID\n')
-    outfd.write('Lon,Lat,Quake_ID,Subfault_ID\n')
-    for t in tstar_data:
-        for n in t.ng_data:
-#            outfd.write('%10.4f%10.4f  %6d  %6d\n' %
-            outfd.write('%.4f,%.4f,%d,%d\n' %
-                        (invall_data[n].lon, invall_data[n].lat, t.ipt, n))
-    outfd.close()
-
-    # write out quake probabilities
-    try:
-        outfd = open(QuakeProbFilename, "w")
-    except IOError, msg:
-        raise RuntimeError(1, "Error opening output file: %s" % msg)
-
-#    outfd.write('  Quake_ID     Ann_Prob     z_max(m)    Mag\n')
-    outfd.write('Quake_ID,Ann_Prob,z_max(m),Mag\n')
-    for t in tstar_data:
-#        outfd.write('%7d %17.5G  %8.5f   %6.2f\n' % (t.ipt, t.zprob, t.zquake, t.mag))
-        outfd.write('%d,%.5G,%.5f,%.2f\n' % (t.ipt, t.zprob, t.zquake, t.mag))
-    outfd.close()
-
-################################################################################
-# This code does exactly what David Burbidge's 'get_multimux' program does.
-################################################################################
-
-def get_multimux(quake_ID, multimux_dir, fault_event_filename):
-    # get the fault name data
-    filename = os.path.join(multimux_dir, FaultNameFilename)
-    try:
-        fd = open(filename, "r")
-        fault_names = [ fn.strip() for fn in fd.readlines() ]
-        fd.close()
-    except IOError, msg:
-        raise RuntimeError(1, "Error reading file: %s" % msg)
-
-    # open the output file
-    try:
-        outfd = open(fault_event_filename, "w")
-    except IOError, msg:
-        raise RuntimeError(1, "Error opening output file: %s" % msg)
-
-    # handle each fault
-    nquake = 0
-    for fn in fault_names:
-        # create the filename for the multimux data file
-        mmx_filename = 'i_multimux-%s' % fn
-        mmx_filename = os.path.join(multimux_dir, mmx_filename)
-
-        # Read all data in file, checking as we go
-        try:
-            infd = open(mmx_filename, "r")
-        except IOError, msg:
-            raise RuntimeError(1, "Error opening file: %s" % msg)
-
-        # check fault name in file is as expected
-        mux_faultname = infd.readline().strip()
-        if mux_faultname != fn:
-            raise RuntimeError(1, "Error reading file")
-
-        # read data
-        while True:
-            # get number of subfaults, EOF means finished
-            try:
-                nsubfault = infd.readline()
-            except IOError:
-                raise RuntimeError(1, "Error reading file")
-
-            if not nsubfault:
-                break
-            nsubfault = int(nsubfault)
-
-            nquake += 1
-            if nquake == quake_ID:
-                outfd.write(' %d\n' % nsubfault)
-                for i in range(nsubfault):
-                    line = infd.readline()
-                    (subfaultname, slip, prob, mag, _) = \
-                                   SpacesPattern.split(line, maxsplit=4)
-                    subfaultname = subfaultname.strip()
-                    slip = float(slip)
-##                    prob = float(prob)
-##                    mag = float(mag)
-                    outfd.write(" %s %g\n" % (subfaultname, slip))
-            else:
-                for i in range(nsubfault):
-                    try:
-                        infd.readline()
-                    except IOError:
-                        raise RuntimeError(1,
-                                           "Something wrong at bottom of file %s" %
-                                           mux_faultname)
-
-        infd.close()
-    outfd.close()
-
-
-################################################################################
-# Code to do the GUI
-#
-# The Frame code is buried under the "if __name__ ..." test since we are going
-# to import this file into verify.py to test the list_quake() and get_multimux()
-# functions.
-################################################################################
-
-if __name__ == '__main__':
-    
-    class MyFrame(wx.Frame):
-        def __init__(self, parent, id, title, pos=wx.DefaultPosition,
-                        size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE):
-            # Make the frame
-            wx.Frame.__init__(self, parent, id, title, pos=(50, 50),
-                                size=(FORM_WIDTH, FORM_HEIGHT),
-                                style=(wx.DEFAULT_FRAME_STYLE &
-                                       ~ (wx.RESIZE_BOX | wx.MAXIMIZE_BOX |
-                                          wx.RESIZE_BORDER)))
-
-            p = self.panel = wx.Panel(self, -1)
-
-            if Imported_PyEmbeddedImage:
-                tsunami = getIcon()
-                icon = tsunami.GetIcon()
-                self.SetIcon(icon)
-            
-            self.Center()
-            self.Show(True)
-
-            # place the 'output dir' textbox
-            Y_OFFSET = START_YOFFSET
-            wx.StaticBox(p, -1, 'output base directory', (3, 1),
-                         size=(BOX_WIDTH, OUTPUT_BOX_HEIGHT))
-            self.txtOutputDir = wx.TextCtrl(p, -1, size=(BOX_WIDTH-10, 20),
-                                            pos=(OUT_TEXT_XOFFSET,
-                                                 Y_OFFSET+OUT_TEXT_YOFFSET))
-            self.txtOutputDir.SetToolTip(wx.ToolTip("Where your data files will be written"))
-            self.txtOutputDir.Bind(wx.EVT_LEFT_DOWN, self.OnOutputDirSelect)
-            Y_OFFSET += 50
-            
-            # start laying out list_quake controls
-            wx.StaticBox(p, -1, 'list_quakes', (3, Y_OFFSET),
-                         size=(BOX_WIDTH, BOX_HEIGHT))
-            sampleList = [ x for (x, y) in Regions ]
-            Y_OFFSET += GEN_YOFFSET
-            wx.StaticText(p, -1, 'Region', pos=(GEN_LABELXOFFSET, Y_OFFSET),
-                          size=(CTL_WIDTH, CTL_HEIGHT), style=wx.ALIGN_RIGHT)
-            self.cbRegion = wx.ComboBox(p, 500, 
-                                        pos=(GEN_TEXTXOFFSET, Y_OFFSET-COMBO_FUDGE),
-                                        size=(100,20),
-                                        choices=sampleList,
-                                        style=wx.CB_DROPDOWN)
-            self.cbRegion.SetEditable(False)
-            Y_OFFSET += GEN_DELTAY 
-            wx.StaticText(p, -1, 'Hazard index',
-                          pos=(GEN_LABELXOFFSET, Y_OFFSET),
-                          size=(CTL_WIDTH, CTL_HEIGHT), style=wx.ALIGN_RIGHT)
-            self.txtTGN = wx.TextCtrl(p, -1, size=(100, 20),
-                                      pos=(GEN_TEXTXOFFSET, Y_OFFSET))
-            Y_OFFSET += GEN_DELTAY 
-            wx.StaticText(p, -1, 'Minimum wave height',
-                          pos=(GEN_LABELXOFFSET, Y_OFFSET),
-                          size=(CTL_WIDTH, CTL_HEIGHT), style=wx.ALIGN_RIGHT)
-            self.txtMinH = wx.TextCtrl(p, -1, size=(100, 20),
-                                       pos=(GEN_TEXTXOFFSET, Y_OFFSET))
-            Y_OFFSET += GEN_DELTAY 
-            wx.StaticText(p, -1, 'Maximum wave height',
-                          pos=(GEN_LABELXOFFSET, Y_OFFSET),
-                          size=(CTL_WIDTH, CTL_HEIGHT), style=wx.ALIGN_RIGHT)
-            self.txtMaxH = wx.TextCtrl(p, -1, size=(100, 20),
-                                       pos=(GEN_TEXTXOFFSET, Y_OFFSET))
-            Y_OFFSET += GEN_DELTAY 
-            x = FORM_WIDTH/2 - BUTTON_WIDTH/2
-            self.btnGenerate = wx.Button(p, label="List",
-                                         pos=(x, Y_OFFSET),
-                                         size=(100, BUTTON_HEIGHT))
-            Y_OFFSET += GEN_DELTAY + BUTTON_HEIGHT/2
-##            self.lstGenerate = SortedListCtrl(p, -1, pos=(8, Y_OFFSET),
-##                                              size=(TEXTLIST_WIDTH,TEXTLIST_HEIGHT),
-##                                              style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.LC_REPORT)
-
-            self.lstGenerate = wx.ListCtrl(p, -1, pos=(8, Y_OFFSET),
-                                           size=(TEXTLIST_WIDTH,TEXTLIST_HEIGHT),
-                                           style=wx.LC_REPORT|wx.LC_SINGLE_SEL)
-            
-            Y_OFFSET += TEXTLIST_HEIGHT + 20
-            self.Bind(wx.EVT_BUTTON, self.GenerateClick, self.btnGenerate)
-            self.lstGenerate.Bind(wx.EVT_LIST_ITEM_SELECTED,
-                                  self.OnItemSelected, self.lstGenerate)
-
-            # start laying out get_multimux controls
-            wx.StaticBox(p, -1, 'multimux_grid', (3, Y_OFFSET),
-                         size=(BOX_WIDTH, BOX2_HEIGHT))
-            Y_OFFSET += 18
-            wx.StaticText(p, -1, 'Quake ID', pos=(GEN_LABELXOFFSET, Y_OFFSET),
-                          size=(CTL_WIDTH, CTL_HEIGHT), style=wx.ALIGN_RIGHT)
-            self.txtQuakeID = wx.TextCtrl(p, -1, size=(100, 20),
-                                          pos=(GEN_TEXTXOFFSET, Y_OFFSET))
-            Y_OFFSET += GEN_DELTAY 
-            x = FORM_WIDTH/2 - BUTTON_WIDTH - DOUBLE_BUTTON_OFFSET
-            self.btnMultimux = wx.Button(p, label="Multimux", pos=(x, Y_OFFSET),
-                                         size=(100, BUTTON_HEIGHT))
-            x = FORM_WIDTH/2 + DOUBLE_BUTTON_OFFSET
-            self.btnGrid = wx.Button(p, label="Grid", pos=(x, Y_OFFSET),
-                                         size=(100, BUTTON_HEIGHT))
-            Y_OFFSET += GEN_DELTAY + BUTTON_HEIGHT/2
-            self.lstMultimux = wx.ListCtrl(p, -1, pos=(8, Y_OFFSET),
-                                           size=(TEXTLIST_WIDTH,TEXTLIST_HEIGHT),
-                                           style=wx.LC_REPORT|wx.LC_SINGLE_SEL)
-            Y_OFFSET += TEXTLIST_HEIGHT + 20
-            self.Bind(wx.EVT_BUTTON, self.MultimuxClick, self.btnMultimux)
-            self.Bind(wx.EVT_BUTTON, self.GridClick, self.btnGrid)
-
-            self.Bind(wx.EVT_CLOSE, self.doStateSave)
-            self.doStateRestore()
-
-        def OnOutputDirSelect(self, event):
-            dlg = wx.DirDialog(self, "Choose an output directory:",
-                  style=wx.DD_DEFAULT_STYLE
-                   #| wx.DD_DIR_MUST_EXIST
-                   #| wx.DD_CHANGE_DIR
-                   )
-
-            # If the user selects OK, then we process the dialog's data.
-            # This is done by getting the path data from the dialog - BEFORE
-            # we destroy it. 
-            if dlg.ShowModal() == wx.ID_OK:
-                self.txtOutputDir.Clear()
-                self.txtOutputDir.WriteText(dlg.GetPath())
-            self.cbRegion.SetFocus()
-            # Only destroy a dialog after you're done with it.
-            dlg.Destroy()
-
-
-        def doStateSave(self, event):
-            """
-            Save state here.
-            """
-            self.cfg['OutputDirectory'] = self.txtOutputDir.GetValue()
-            self.cfg['Region'] = self.cbRegion.GetValue()
-            self.cfg['GaugeNumber'] = self.txtTGN.GetValue()
-            self.cfg['MinimumHeight'] = self.txtMinH.GetValue()
-            self.cfg['MaximumHeight'] = self.txtMaxH.GetValue()
-            self.cfg.save()
-            
-            event.Skip(True)
-
-        def doStateRestore(self):
-            """
-            Restore state here - globals have been set and tested sane
-            """
-            global Region, GaugeNumber, MinimumHeight, MaximumHeight
-
-            cfg = Config(ConfigFilename)
-            output_dir = cfg['OutputDirectory']
-            Region = cfg['Region']
-            GaugeNumber = cfg['GaugeNumber']
-            if GaugeNumber:
-                GaugeNumber = int(GaugeNumber)
-            MinimumHeight = cfg['MinimumHeight']
-            if MinimumHeight:
-                MinimumHeight = float(MinimumHeight)
-            MaximumHeight = cfg['MaximumHeight']
-            if MaximumHeight:
-                MaximumHeight = float(MaximumHeight)
-
-            self.cfg = cfg
-
-            region_name = None
-            for (name, dir) in Regions:
-                if name == Region:
-                    region_name = name
-            if not region_name:
-                Region = ''
-
-            if output_dir:
-                self.txtOutputDir.WriteText(output_dir)
-            self.cbRegion.SetStringSelection(Region)
-            if GaugeNumber:
-                self.txtTGN.WriteText(str(GaugeNumber))
-            if MinimumHeight:
-                self.txtMinH.WriteText(str(MinimumHeight))
-            if MaximumHeight:
-                self.txtMaxH.WriteText(str(MaximumHeight))
-            
-
-        def OnItemSelected(self, event):
-            item = self.lstGenerate.GetItem(event.m_itemIndex, 0)
-            self.txtQuakeID.SetValue(item.GetText())
-
-        def error(self, msg):
-            dlg = wx.MessageDialog(self, msg, 'Error',
-                                   wx.OK | wx.ICON_INFORMATION)
-            dlg.ShowModal()
-            dlg.Destroy()
-
-        ######
-        # Call the list_quakes function.
-        ######
-        def GenerateClick(self, event):
-            global ResultSubdir, Region, GaugeNumber, MinimumHeight, MaximumHeight
-            
-            # check that everything has been entered correctly
-            output_base_dir = self.txtOutputDir.GetValue()
-            if len(output_base_dir) == 0:
-                self.error('You must select an output base directory first')
-                return
-
-            region_select = self.cbRegion.GetValue()
-            if len(region_select) == 0:
-                self.error('You must select a region first')
-                return
-
-            try:
-                gauge_number = int(self.txtTGN.GetValue())
-            except:
-                self.error("You must enter a Hazard Index Number")
-                return
-
-            try:
-                min_height = float(self.txtMinH .GetValue())
-            except:
-                self.error("You must enter a minimum wave height in metres (eg, 1.3)")
-                return
-
-            try:
-                max_height = float(self.txtMaxH.GetValue())
-            except:
-                self.error("You must enter a maximum wave height in metres (eg, 1.8)")
-                return
-            if min_height > max_height:
-                self.error("Minimum wave height must be less than maximum height")
-                return
-
-            # set directory names
-            basename = None
-            region_name = None
-            for (name, dir) in Regions:
-                if name == region_select:
-                    region_name = name
-                    basename = dir
-            base_directory = os.path.join(BaseDirectory, basename)
-            if not os.path.exists(base_directory):
-                self.error("Sorry, region %s doesn't exist yet (%s)" %
-                           (region_name, base_directory))
-                return
-            tFilesDir = os.path.join(base_directory, 'Tfiles')
-            multimuxDir = os.path.join(base_directory, 'multimux')
-
-            # create a sub-directory for the result files
-            ResultSubdir = os.path.join(output_base_dir,
-                                        'Results_%s_%d_%.2f_%.2f' %
-                                        (region_select, gauge_number,
-                                         min_height, max_height))
-            try:
-                shutil.rmtree(ResultSubdir)
-            except:
-                pass
-            try:
-                os.mkdir(ResultSubdir)
-            except WindowsError, msg:
-                self.error("Sorry, don't seem to be able to make "
-                           "the result directory '%s':\n%s" %
-                           (ResultSubdir, str(msg)))
-                return
-            except:
-                self.error("Some sort of error making the result directory '%s'" %
-                           ResultSubdir)
-                return
-
-            # set names of the output files (in dir '<wherever>/Results*')
-            faultxy_filename = os.path.join(ResultSubdir, FaultXYFilename)
-            quakeprob_filename = os.path.join(ResultSubdir, QuakeProbFilename)
-
-            # now check that gauge number is valid
-            gaugeFile = os.path.join(tFilesDir, 'T-%05d' % gauge_number)
-            if not os.path.exists(gaugeFile):
-                self.error("T file for hazard %d doesn't exist" % gauge_number)
-                return
-
-            # check we have an i_invall file
-            invallFile = os.path.join(multimuxDir, 'i_invall')
-            if not os.path.exists(invallFile):
-                self.error("'i_invall' file doesn't exist: %s" % invallFile)
-                return
-
-            # save region, hazard #, min and max heights to globals
-            Region = region_select
-            GaugeNumber = gauge_number
-            MinimumHeight = min_height
-            MaximumHeight = max_height
-
-            # clear the Quake ID textbox
-            self.txtQuakeID.SetValue('')
-            
-            # now process the data we have
-            # clear output list
-            self.lstGenerate.ClearAll()
-            # delete output files
-            try:
-                os.unlink(FaultXYFilename)
-            except:
-                pass
-            try:
-                os.unlink(QuakeProbFilename)
-            except:
-                pass
-
-            ####################################################################
-            # reset button label, hourglass the cursor
-            self.btnGenerate.SetLabel('Listing ...')
-            self.panel.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
-            
-            wx.Yield()          # allow GUI refresh
-
-            # generate output files
-            try:
-                list_quakes(gauge_number, min_height, max_height, invallFile,
-                            gaugeFile, faultxy_filename, quakeprob_filename)        
-            except RuntimeError, msg:
-                self.error("Error in list_quakes module: %s" % msg)
-                self.panel.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
-                self.btnGenerate.SetLabel('List')
-                return
-            # put cursor back to normal, button label back to normal
-            self.panel.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
-            self.btnGenerate.SetLabel('List')
-            ####################################################################
-
-            # list result file, if any
-            if not os.path.exists(quakeprob_filename):
-                self.error("Error generating data: file '%s' not found" %
-                           quakeprob_filename)
-                return
-            in_fd = open(quakeprob_filename, 'r')
-            lines = in_fd.readlines()
-            in_fd.close()
-            hdr = lines[0].split(',')
-            for (i, h) in enumerate(hdr):
-                self.lstGenerate.InsertColumn(i, h.strip())
-            for (i, l) in enumerate(lines[1:]):
-                l = l.split(',')
-                index = self.lstGenerate.InsertStringItem(sys.maxint, l[0].strip())
-                for (ii, ll) in enumerate(l[1:]):
-                    self.lstGenerate.SetStringItem(index, ii+1, ll.strip())
-
-##            for (i, l) in enumerate(lines[1:]):
-##                l = l.split(',')
-##                index = self.lstGenerate.InsertStringItem(sys.maxint, l[0].strip())
-##                for (ii, ll) in enumerate(l[1:]):
-##                    self.lstGenerate.SetStringItem(index, ii+1, ll.strip())
-##                self.lstGenerate.SetItemData(index, i)
-
-                    
-            column_width = FORM_WIDTH / len(hdr) - 20
-            for i in range(len(hdr)):
-                self.lstGenerate.SetColumnWidth(i, column_width)
-
-        ######
-        # Call the get_multimux function.
-        ######
-        def MultimuxClick(self, event):
-            # check we have a quake ID
-            quake_ID = self.txtQuakeID.GetValue()
-            if len(quake_ID) == 0:
-                self.error('You must enter a quake ID first')
-                return
-            try:
-                quake_ID = int(quake_ID)
-            except:
-                self.error("You must enter a Quake ID")
-                return
-
-            region_select = self.cbRegion.GetValue()
-            if len(region_select) == 0:
-                self.error('You must select a region first')
-                return
-
-            region_dir_name = None
-            for (disp, real) in Regions:
-                if disp == region_select:
-                    region_dir_name = real
-                    break
-            if region_dir_name is None:
-                self.error('INTERNAL ERROR: region_dir_name is None?!')
-                return
-
-            multimux_dir = os.path.join(BaseDirectory, region_dir_name, 'multimux')
-
-##            # delete any output files lying around
-##            o_files = glob.glob('%s/event_[0-9]*.list' % ResultSubdir)
-##            for of in o_files:
-##                try:
-##                    os.unlink(of)
-##                except:
-##                    pass
-
-            ####################################################################
-            # clear list, set button label, hourglass the cursor
-            self.lstMultimux.ClearAll()
-            self.lstMultimux.InsertColumn(0, '')
-            self.btnMultimux.SetLabel('Multimuxing ...')
-            self.panel.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
-
-            fault_event_filename = ('%s/event_%6.6d.list' %
-                                    (ResultSubdir, quake_ID))
-            wx.Yield()          # allow GUI refresh
-
-            try:
-                get_multimux(quake_ID, multimux_dir, fault_event_filename)
-            except RuntimeError, msg:
-                self.error("Error in get_multimux module: %s" % msg)
-                self.panel.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
-                self.btnMultimux.SetLabel('Multimux')
-                return
-            # cursor and button label to normal
-            self.panel.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
-            self.btnMultimux.SetLabel('Multimux')
-            ####################################################################
-
-            # list resultant files, if any
-            if not os.path.exists(fault_event_filename):
-                self.error("Error generating data: file %s not found" %
-                           fault_event_filename)
-                return
-            
-            in_fd = open(fault_event_filename, 'r')
-            lines = in_fd.readlines()
-            in_fd.close()
-            hdr = lines[0].strip()
-            hdr = SpacesPattern.split(hdr)
-            for (i, h) in enumerate(hdr):
-                self.lstMultimux.InsertColumn(i, h)
-            for (i, l) in enumerate(lines[1:]):
-                l = l.strip()
-                l = SpacesPattern.split(l)
-                index = self.lstMultimux.InsertStringItem(sys.maxint, l[0])
-                for (ii, ll) in enumerate(l[1:]):
-                    self.lstMultimux.SetStringItem(index, ii+1, ll)
-            column_width = FORM_WIDTH / 2 - 30
-            for i in range(2):
-                self.lstMultimux.SetColumnWidth(i, column_width)
-
-            # generate the urs_filenames.py module from 'lines' data
-            # get data from lines we read previously
-            last_weight = None
-            filenames = []
-            for line in lines[1:]:
-                (_, filename, weight) = SpacesPattern.split(line)
-                weight = float(weight)
-                if last_weight:
-                    if last_weight != weight:
-                        self.error("In file '%s', inconsistent weight, "
-                                   "was %.4f, expected %.4f" % (weight, last_weight))
-                        return
-                last_weight = weight
-                filenames.append(filename)
-            # write data to the file
-            urs_filename = '%s/%s' % (ResultSubdir, URSDataFilename % quake_ID)
-            try:
-                out_fd = open(urs_filename, "w")
-            except IOError, msg:
-                self.error("Error opening output file %s': %s" %
-                           (urs_filename, msg))
-                return
-            if last_weight and filenames:
-                out_fd.write('# Data for region %s,\n'
-                             '#          hazard %d,\n'
-                             '#          min height %.2f,\n'
-                             '#          max height %.2f,\n'
-                             '#          quake ID %d\n' %
-                             (Region, GaugeNumber, MinimumHeight,
-                              MaximumHeight, quake_ID))
-                out_fd.write('# Generated on %s.\n' % time.asctime(time.localtime()))
-                out_fd.write('\n')
-                out_fd.write('import os.path\n')
-                out_fd.write('\n')
-                out_fd.write('def getInfo(base_directory):\n')
-                out_fd.write('    """\n')
-                out_fd.write('    Return the weight factor and list of URS data filenames\n')
-                out_fd.write('\n')
-                out_fd.write('        (weight_factor, [filenames]) <- get_urs_data(base_directory)\n')
-                out_fd.write('\n')
-                out_fd.write('    where base_directory is the path to the mux files.\n')
-                out_fd.write('    """\n')
-                out_fd.write('\n')
-                out_fd.write('    weight_factor = %f\n' % last_weight)
-                out_fd.write('    mux_filenames = [')
-                if filenames:
-                    for fn in filenames[:-1]:
-                        out_fd.write('"%%s" %% os.path.join(base_directory, "%s"),\n                     ' % fn)
-                    out_fd.write('"%%s" %% os.path.join(base_directory, "%s")\n                    ' % filenames[-1])
-                out_fd.write(']\n')
-                out_fd.write('\n')
-                out_fd.write('    return (weight_factor, mux_filenames)\n')
-            out_fd.close() 
-            
-        ######
-        # Call the get_grid function.
-        ######
-        def GridClick(self, event):
-            # check we have a quake ID
-            quake_ID = self.txtQuakeID.GetValue()
-            if len(quake_ID) == 0:
-                self.error('You must enter a quake ID first')
-                return
-            try:
-                quake_ID = int(quake_ID)
-            except:
-                self.error("You must enter a Quake ID")
-                return
-
-            region_select = self.cbRegion.GetValue()
-            if len(region_select) == 0:
-                self.error('You must select a region first')
-                return
-
-            region_dir_name = None
-            for (disp, real) in Regions:
-                if disp == region_select:
-                    region_dir_name = real
-                    break
-            if region_dir_name is None:
-                self.error('INTERNAL ERROR: region_dir_name is None?!')
-                return
-
-            multimux_dir = os.path.join(BaseDirectory, region_dir_name, 'multimux')
-            grid_dir = os.path.join(BaseDirectory, region_dir_name, 'static_2m')
-
-##            # delete any output files lying around
-##            o_files = glob.glob('%s/event_[0-9]*.list' % ResultSubdir)
-##            for of in o_files:
-##                try:
-##                    os.unlink(of)
-##                except:
-##                    pass
-
-            ####################################################################
-            # clear list, set button label, hourglass the cursor
-            self.lstMultimux.ClearAll()
-            self.lstMultimux.InsertColumn(0, '')
-            self.btnGrid.SetLabel('Gridding ...')
-            self.panel.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
-
-            fault_event_filename = ('%s/event_%6.6d.list' %
-                                    (ResultSubdir, quake_ID))
-            wx.Yield()          # allow GUI refresh
-
-            try:
-                get_multimux(quake_ID, multimux_dir, fault_event_filename)
-            except RuntimeError, msg:
-                self.error("Error in get_multimux module: %s" % msg)
-                self.panel.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
-                self.btnGrid.SetLabel('Grid')
-                return
-            # cursor and button label to normal
-            self.panel.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
-            self.btnGrid.SetLabel('Grid')
-            ####################################################################
-
-            # list resultant files, if any
-            if not os.path.exists(fault_event_filename):
-                self.error("Error generating data: file %s not found" %
-                           fault_event_filename)
-                return
-
-            # read output data file
-            in_fd = open(fault_event_filename, 'r')
-            lines = in_fd.readlines()
-            in_fd.close()
-            # get header items, display them
-            hdr = lines[0].strip()
-            hdr = SpacesPattern.split(hdr)
-            for (i, h) in enumerate(hdr):
-                self.lstMultimux.InsertColumn(i, h)
-            # display resultant data, collect filenames and weight_factor                
-            weight_factor = None
-            wf_error = False        # True if there was a weight_factor error
-            filenames = []
-            for (i, l) in enumerate(lines[1:]):
-                l = l.strip()
-                l = SpacesPattern.split(l)
-                fname = l[0].replace('.grd-z-mux2', '.grd')
-                filenames.append(fname)
-                index = self.lstMultimux.InsertStringItem(sys.maxint, fname)
-                for (ii, ll) in enumerate(l[1:]):
-                    self.lstMultimux.SetStringItem(index, ii+1, ll)
-                if weight_factor:
-                    if weight_factor != float(l[1]):
-                        wf_error = True
-                else:
-                    weight_factor = float(l[1])
-            column_width = FORM_WIDTH / 2 - 30
-            for i in range(2):
-                self.lstMultimux.SetColumnWidth(i, column_width)
-
-            if wf_error:
-                self.error('Weight factor is not the same for all files!')
-                return
-
-            if not filenames:
-                self.error('No grid files found!')
-                return
-
-            # generate the bash script param_file.
-            out_name = GridBashScriptName % quake_ID
-            grid_filename = '%s/%s' % (ResultSubdir, out_name)
-            
-            try:
-                out_fd = open(grid_filename, "w")
-            except IOError, msg:
-                self.error("Error opening output file %s': %s" %
-                           (grid_filename, msg))
-                return
-
-            out_fd.write('GENERATED=%s\n' % time.asctime(time.localtime()))
-            out_fd.write('REGION=%s\n' % Region)
-            out_fd.write('HAZARD_INDEX=%d\n' % GaugeNumber)
-            out_fd.write('WAVE_HEIGHTS=[%.2f,%.2f]\n' % (MinimumHeight, MaximumHeight))
-            out_fd.write('QUAKE_ID=%d\n' % quake_ID)
-            out_fd.write('WEIGHT_FACTOR=%f\n' % weight_factor)
-            out_fd.write('DATA_PATH=%s\n' % grid_dir)
-            for fn in filenames[1:]:
-                owning_dir = filenames[0].split('-')[0]
-                out_fd.write('GRID=%s\n' % (os.path.join(owning_dir, fn)))
-            out_fd.write('FAULT=%s\n' % owning_dir)
-            
-
-    
-    app = wx.App()
-    frame = MyFrame(None, -1, '%s %s' % (APP_NAME, APP_VERSION),
-                    size=(FORM_WIDTH, FORM_HEIGHT))
-    app.SetTopWindow(frame)
-    app.MainLoop()
