Changeset 1042


Ignore:
Timestamp:
Mar 8, 2005, 5:35:19 PM (19 years ago)
Author:
steve
Message:
 
File:
1 edited

Legend:

Unmodified
Added
Removed
  • inundation/ga/storm_surge/pyvolution/shallow_water.py

    r1037 r1042  
    2121The quantities are
    2222
    23 symbol    variable name    explanation 
     23symbol    variable name    explanation
    2424x         x                horizontal distance from origin [m]
    25 y         y                vertical distance from origin [m] 
     25y         y                vertical distance from origin [m]
    2626z         elevation        elevation of bed on which flow is modelled [m]
    2727h         height           water height above z [m]
     
    4545
    4646Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
    47 Geoscience Australia, 2004   
     47Geoscience Australia, 2004
    4848"""
    4949
     
    6666
    6767        conserved_quantities = ['stage', 'xmomentum', 'ymomentum']
    68         other_quantities = ['elevation', 'friction'] 
    69        
     68        other_quantities = ['elevation', 'friction']
     69
    7070        Generic_domain.__init__(self, coordinates, vertices, boundary,
    7171                                conserved_quantities, other_quantities,
     
    8484        #Stored output
    8585        self.store = False
    86         self.format = 'sww'   
     86        self.format = 'sww'
    8787        self.smooth = True
    8888
    89         #Reduction operation for get_vertex_values             
     89        #Reduction operation for get_vertex_values
    9090        #from util import mean
    91         #self.reduction = mean 
     91        #self.reduction = mean
    9292        self.reduction = min  #Looks better near steep slopes
    93        
     93
    9494        self.quantities_to_be_stored = ['stage']
    9595
    96        
     96
    9797        #Establish shortcuts to relevant quantities (for efficiency)
    9898        #self.w = self.quantities['stage']
    99         #self.uh = self.quantities['xmomentum']                 
    100         #self.vh = self.quantities['ymomentum']                         
    101         #self.z = self.quantities['elevation']         
    102         #self.eta = self.quantities['friction']                 
     99        #self.uh = self.quantities['xmomentum']
     100        #self.vh = self.quantities['ymomentum']
     101        #self.z = self.quantities['elevation']
     102        #self.eta = self.quantities['friction']
    103103
    104104    def check_integrity(self):
     
    113113        msg = 'Third conserved quantity must be "ymomentum"'
    114114        assert self.conserved_quantities[2] == 'ymomentum', msg
    115        
     115
    116116
    117117    def compute_fluxes(self):
     
    122122    def distribute_to_vertices_and_edges(self):
    123123        #Call correct module function
    124         #(either from this module or C-extension)       
     124        #(either from this module or C-extension)
    125125        distribute_to_vertices_and_edges(self)
    126126
    127127
    128     #FIXME: Under construction   
     128    #FIXME: Under construction
    129129#     def set_defaults(self):
    130130#         """Set default values for uninitialised quantities.
     
    139139#             if not self.quantities.has_key(name):
    140140#                 if name == 'stage':
    141                    
     141
    142142#                     if self.quantities.has_key('elevation'):
    143143#                         z = self.quantities['elevation'].vertex_values
    144 #                         self.set_quantity(name, z) 
     144#                         self.set_quantity(name, z)
    145145#                     else:
    146 #                         self.set_quantity(name, 0.0)                       
    147 #                 else:   
     146#                         self.set_quantity(name, 0.0)
     147#                 else:
    148148#                     self.set_quantity(name, 0.0)
    149                    
     149
    150150
    151151
     
    161161#         #            w[k, i] = z[k, i]
    162162
    163                    
     163
    164164#         #self.quantities['stage'].interpolate()
    165                
     165
    166166
    167167
     
    170170        """
    171171
    172         #Call check integrity here rather than from user scripts 
     172        #Call check integrity here rather than from user scripts
    173173        #self.check_integrity()
    174        
    175        
    176         #Initial update of vertex and edge values before any storage
    177         #and or visualisation
     174
     175
     176        #Initial update of vertex and edge values before any storage
     177        #and or visualisation
    178178        self.distribute_to_vertices_and_edges()
    179        
    180                
     179
     180
    181181        #Initialise real time viz if requested
    182182        if self.visualise is True and self.time == 0.0:
     
    184184            visualise.create_surface(self)
    185185
    186         #Store model data, e.g. for visualisation   
     186        #Store model data, e.g. for visualisation
    187187        if self.store is True and self.time == 0.0:
    188188            self.initialise_storage()
     
    201201                visualise.update(self)
    202202
    203             #Store model data, e.g. for subsequent visualisation   
     203            #Store model data, e.g. for subsequent visualisation
    204204            if self.store is True:
    205205                self.store_timestep(self.quantities_to_be_stored)
    206                
    207                 #FIXME: Could maybe be taken from specified list 
    208                 #of 'store every step' quantities       
    209 
    210             #Pass control on to outer loop for more specific actions   
     206
     207                #FIXME: Could maybe be taken from specified list
     208                #of 'store every step' quantities
     209
     210            #Pass control on to outer loop for more specific actions
    211211            yield(t)
    212        
    213 
    214     def initialise_storage(self):       
     212
     213
     214    def initialise_storage(self):
    215215        """Create and initialise self.writer object for storing data.
    216216        Also, save x,y and bed elevation
    217         """
     217        """
    218218
    219219        import data_manager
    220        
     220
    221221        #Initialise writer
    222222        self.writer = data_manager.get_dataobject(self, mode = 'w')
     
    233233        """
    234234        self.writer.store_timestep(name)
    235        
     235
    236236
    237237#Rotation of momentum vector
     
    241241
    242242    If direction is negative the rotation is inverted.
    243    
     243
    244244    Input vector is preserved
    245245
     
    248248
    249249    from Numeric import zeros, Float
    250    
     250
    251251    assert len(q) == 3,\
    252252           'Vector of conserved quantities must have length 3'\
     
    259259
    260260    assert l == 2, 'Normal vector must have 2 components'
    261    
    262  
     261
     262
    263263    n1 = normal[0]
    264     n2 = normal[1]   
    265    
     264    n2 = normal[1]
     265
    266266    r = zeros(len(q), Float) #Rotated quantities
    267267    r[0] = q[0]              #First quantity, height, is not rotated
     
    273273    r[1] =  n1*q[1] + n2*q[2]
    274274    r[2] = -n2*q[1] + n1*q[2]
    275    
     275
    276276    return r
    277277
     
    279279
    280280####################################
    281 # Flux computation       
    282 def flux_function(normal, ql, qr, zl, zr): 
     281# Flux computation
     282def flux_function(normal, ql, qr, zl, zr):
    283283    """Compute fluxes between volumes for the shallow water wave equation
    284284    cast in terms of w = h+z using the 'central scheme' as described in
     
    313313        u_left = 0.0  #Could have been negative
    314314        h_left = 0.0
    315     else:   
     315    else:
    316316        u_left  = uh_left/h_left
    317317
     
    325325        u_right = 0.0  #Could have been negative
    326326        h_right = 0.0
    327     else:   
     327    else:
    328328        u_right  = uh_right/h_right
    329329
    330330    vh_left  = q_left[2]
    331     vh_right = q_right[2]       
    332 
    333     soundspeed_left  = sqrt(g*h_left) 
     331    vh_right = q_right[2]
     332
     333    soundspeed_left  = sqrt(g*h_left)
    334334    soundspeed_right = sqrt(g*h_right)
    335335
    336336    #Maximal wave speed
    337337    s_max = max(u_left+soundspeed_left, u_right+soundspeed_right, 0)
    338    
    339     #Minimal wave speed       
     338
     339    #Minimal wave speed
    340340    s_min = min(u_left-soundspeed_left, u_right-soundspeed_right, 0)
    341341
     
    346346    flux_right = array([u_right*h_right,
    347347                        u_right*uh_right + 0.5*g*h_right**2,
    348                         u_right*vh_right])   
     348                        u_right*vh_right])
    349349
    350350    denom = s_max-s_min
     
    352352        edgeflux = array([0.0, 0.0, 0.0])
    353353        max_speed = 0.0
    354     else:   
     354    else:
    355355        edgeflux = (s_max*flux_left - s_min*flux_right)/denom
    356356        edgeflux += s_max*s_min*(q_right-q_left)/denom
     
    359359        max_speed = max(abs(s_max), abs(s_min))
    360360
    361     return edgeflux, max_speed       
     361    return edgeflux, max_speed
    362362
    363363
     
    370370    Fluxes across each edge are scaled by edgelengths and summed up
    371371    Resulting flux is then scaled by area and stored in
    372     explicit_update for each of the three conserved quantities 
    373     stage, xmomentum and ymomentum   
     372    explicit_update for each of the three conserved quantities
     373    stage, xmomentum and ymomentum
    374374
    375375    The maximal allowable speed computed by the flux_function for each volume
     
    379379    Post conditions:
    380380      domain.explicit_update is reset to computed flux values
    381       domain.timestep is set to the largest step satisfying all volumes. 
     381      domain.timestep is set to the largest step satisfying all volumes.
    382382    """
    383383
     
    386386
    387387    N = domain.number_of_elements
    388    
     388
    389389    #Shortcuts
    390390    Stage = domain.quantities['stage']
    391391    Xmom = domain.quantities['xmomentum']
    392392    Ymom = domain.quantities['ymomentum']
    393     Bed = domain.quantities['elevation']       
     393    Bed = domain.quantities['elevation']
    394394
    395395    #Arrays
     
    397397    xmom =  Xmom.edge_values
    398398    ymom =  Ymom.edge_values
    399     bed =   Bed.edge_values   
     399    bed =   Bed.edge_values
    400400
    401401    stage_bdry = Stage.boundary_values
    402402    xmom_bdry =  Xmom.boundary_values
    403403    ymom_bdry =  Ymom.boundary_values
    404    
     404
    405405    flux = zeros(3, Float) #Work array for summing up fluxes
    406406
    407407    #Loop
    408     timestep = float(sys.maxint)   
     408    timestep = float(sys.maxint)
    409409    for k in range(N):
    410410
     
    416416
    417417            #Quantities at neighbour on nearest face
    418             n = domain.neighbours[k,i] 
     418            n = domain.neighbours[k,i]
    419419            if n < 0:
    420420                m = -n-1 #Convert negative flag to index
    421421                qr = [stage_bdry[m], xmom_bdry[m], ymom_bdry[m]]
    422422                zr = zl #Extend bed elevation to boundary
    423             else:   
     423            else:
    424424                m = domain.neighbour_edges[k,i]
    425425                qr = [stage[n, m], xmom[n, m], ymom[n, m]]
    426                 zr = bed[n, m]               
    427 
    428                
    429             #Outward pointing normal vector   
     426                zr = bed[n, m]
     427
     428
     429            #Outward pointing normal vector
    430430            normal = domain.normals[k, 2*i:2*i+2]
    431431
     
    447447        Ymom.explicit_update[k] = flux[2]
    448448
    449    
    450     domain.timestep = timestep   
     449
     450    domain.timestep = timestep
    451451
    452452
     
    459459
    460460    N = domain.number_of_elements
    461    
     461
    462462    #Shortcuts
    463463    Stage = domain.quantities['stage']
    464464    Xmom = domain.quantities['xmomentum']
    465465    Ymom = domain.quantities['ymomentum']
    466     Bed = domain.quantities['elevation']       
    467 
    468     timestep = float(sys.maxint)   
     466    Bed = domain.quantities['elevation']
     467
     468    timestep = float(sys.maxint)
    469469    from shallow_water_ext import compute_fluxes
    470470    domain.timestep = compute_fluxes(timestep, domain.epsilon, domain.g,
     
    472472                                     domain.neighbour_edges,
    473473                                     domain.normals,
    474                                      domain.edgelengths,                       
     474                                     domain.edgelengths,
    475475                                     domain.radii,
    476476                                     domain.areas,
    477                                      Stage.edge_values, 
    478                                      Xmom.edge_values, 
    479                                      Ymom.edge_values, 
    480                                      Bed.edge_values,   
     477                                     Stage.edge_values,
     478                                     Xmom.edge_values,
     479                                     Ymom.edge_values,
     480                                     Bed.edge_values,
    481481                                     Stage.boundary_values,
    482482                                     Xmom.boundary_values,
     
    485485                                     Xmom.explicit_update,
    486486                                     Ymom.explicit_update)
    487                                      
     487
    488488
    489489####################################
     
    496496
    497497    It will ensure that h (w-z) is always non-negative even in the
    498     presence of steep bed-slopes by taking a weighted average between shallow 
     498    presence of steep bed-slopes by taking a weighted average between shallow
    499499    and deep cases.
    500    
     500
    501501    In addition, all conserved quantities get distributed as per either a
    502502    constant (order==1) or a piecewise linear function (order==2).
    503    
     503
    504504    FIXME: more explanation about removal of artificial variability etc
    505505
     
    510510    Postcondition
    511511      Conserved quantities defined at vertices
    512    
     512
    513513    """
    514514
     
    523523        elif domain.order == 2:
    524524            Q.extrapolate_second_order()
    525             Q.limit()                               
     525            Q.limit()
    526526        else:
    527527            raise 'Unknown order'
    528        
     528
    529529    #Take bed elevation into account when water heights are small
    530530    balance_deep_and_shallow(domain)
     
    534534        Q = domain.quantities[name]
    535535        Q.interpolate_from_vertices_to_edges()
    536                    
     536
    537537
    538538
     
    543543
    544544    #FIXME: Experimental (from old version). Not in use at the moment
    545    
     545
    546546    #Shortcuts
    547547    wv = domain.quantities['stage'].vertex_values
    548548    zv = domain.quantities['elevation'].vertex_values
    549549    xmomv = domain.quantities['xmomentum'].vertex_values
    550     ymomv = domain.quantities['ymomentum'].vertex_values           
     550    ymomv = domain.quantities['ymomentum'].vertex_values
    551551    hv = wv - zv  #Water depths at vertices
    552552
     
    554554    for k in range(domain.number_of_elements):
    555555        hmax = max(hv[k, :])
    556        
     556
    557557        if hmax < domain.minimum_allowed_height:
    558558            #Control stage
     
    561561            #Control momentum
    562562            xmomv[k,:] = ymomv[k,:] = 0.0
    563    
     563
    564564
    565565def protect_against_infinitesimal_and_negative_heights(domain):
    566566    """Protect against infinitesimal heights and associated high velocities
    567567    """
    568    
     568
    569569    #FIXME: Look here for error
    570    
     570
    571571    #Shortcuts
    572572    wc = domain.quantities['stage'].centroid_values
    573573    zc = domain.quantities['elevation'].centroid_values
    574574    xmomc = domain.quantities['xmomentum'].centroid_values
    575     ymomc = domain.quantities['ymomentum'].centroid_values           
    576     hc = wc - zc  #Water depths at centroids   
     575    ymomc = domain.quantities['ymomentum'].centroid_values
     576    hc = wc - zc  #Water depths at centroids
    577577
    578578    #print zc
    579     #print '1', wc     
     579    #print '1', wc
    580580    #Update
    581581    for k in range(domain.number_of_elements):
    582582
    583         if hc[k] < domain.minimum_allowed_height: 
     583        if hc[k] < domain.minimum_allowed_height:
    584584            #Control stage
    585585            wc[k] = zc[k]
     
    587587            #Control momentum
    588588            xmomc[k] = ymomc[k] = 0.0
    589        
    590     #print '2', wc             
     589
     590    #print '2', wc
    591591
    592592
     
    594594    """Protect against infinitesimal heights and associated high velocities
    595595    """
    596    
     596
    597597    #Shortcuts
    598598    wc = domain.quantities['stage'].centroid_values
    599599    zc = domain.quantities['elevation'].centroid_values
    600600    xmomc = domain.quantities['xmomentum'].centroid_values
    601     ymomc = domain.quantities['ymomentum'].centroid_values           
     601    ymomc = domain.quantities['ymomentum'].centroid_values
    602602
    603603    from shallow_water_ext import protect
    604604
    605605    protect(domain.minimum_allowed_height, wc, zc, xmomc, ymomc)
    606    
    607 
    608 
    609 def h_limiter(domain):       
     606
     607
     608
     609def h_limiter(domain):
    610610    """Limit slopes for each volume to eliminate artificial variance
    611611    introduced by e.g. second order extrapolator
    612    
     612
    613613    limit on h = w-z
    614614
     
    621621    N = domain.number_of_elements
    622622    beta_h = domain.beta_h
    623    
     623
    624624    #Shortcuts
    625625    wc = domain.quantities['stage'].centroid_values
    626626    zc = domain.quantities['elevation'].centroid_values
    627627    hc = wc - zc
    628    
     628
    629629    wv = domain.quantities['stage'].vertex_values
    630630    zv = domain.quantities['elevation'].vertex_values
    631631    hv = wv-zv
    632632
    633     hvbar = zeros(hv.shape, Float) #h-limited values 
    634    
     633    hvbar = zeros(hv.shape, Float) #h-limited values
     634
    635635    #Find min and max of this and neighbour's centroid values
    636636    hmax = zeros(hc.shape, Float)
    637     hmin = zeros(hc.shape, Float)       
    638    
     637    hmin = zeros(hc.shape, Float)
     638
    639639    for k in range(N):
    640640        hmax[k] = hmin[k] = hc[k]
     
    643643            if n >= 0:
    644644                hn = hc[n] #Neighbour's centroid value
    645                
     645
    646646                hmin[k] = min(hmin[k], hn)
    647647                hmax[k] = max(hmax[k], hn)
    648      
    649    
     648
     649
    650650    #Diffences between centroids and maxima/minima
    651     dhmax = hmax - hc 
     651    dhmax = hmax - hc
    652652    dhmin = hmin - hc
    653        
     653
    654654    #Deltas between vertex and centroid values
    655655    dh = zeros(hv.shape, Float)
     
    657657        dh[:,i] = hv[:,i] - hc
    658658
    659     #Phi limiter   
     659    #Phi limiter
    660660    for k in range(N):
    661        
     661
    662662        #Find the gradient limiter (phi) across vertices
    663663        phi = 1.0
     
    666666            if (dh[k,i] > 0): r = dhmax[k]/dh[k,i]
    667667            if (dh[k,i] < 0): r = dhmin[k]/dh[k,i]
    668            
    669             phi = min( min(r*beta_h, 1), phi )   
     668
     669            phi = min( min(r*beta_h, 1), phi )
    670670
    671671        #Then update using phi limiter
    672         for i in range(3):           
     672        for i in range(3):
    673673            hvbar[k,i] = hc[k] + phi*dh[k,i]
    674674
     
    677677
    678678
    679 def h_limiter_c(domain):       
     679def h_limiter_c(domain):
    680680    """Limit slopes for each volume to eliminate artificial variance
    681681    introduced by e.g. second order extrapolator
    682    
     682
    683683    limit on h = w-z
    684684
     
    693693    N = domain.number_of_elements
    694694    beta_h = domain.beta_h
    695    
     695
    696696    #Shortcuts
    697697    wc = domain.quantities['stage'].centroid_values
    698698    zc = domain.quantities['elevation'].centroid_values
    699699    hc = wc - zc
    700    
     700
    701701    wv = domain.quantities['stage'].vertex_values
    702702    zv = domain.quantities['elevation'].vertex_values
     
    709709    return hvbar
    710710
    711                                            
     711
    712712def balance_deep_and_shallow(domain):
    713713    """Compute linear combination between stage as computed by
    714     gradient-limiters limiting using w, and stage computed as 
     714    gradient-limiters limiting using w, and stage computed as
    715715    constant height above bed and limited using h.
    716716    The former takes precedence when heights are large compared to the
     
    721721    modes.
    722722
    723     The h-limiter is always applied irrespective of the order. 
     723    The h-limiter is always applied irrespective of the order.
    724724    """
    725725
    726726    #New idea.
    727727    #
    728     # In the presence and near of bedslope it is necessary to 
    729     # limit slopes based on differences in h rather than w 
     728    # In the presence and near of bedslope it is necessary to
     729    # limit slopes based on differences in h rather than w
    730730    # (which is what is needed away from the bed).
    731731    #
     
    733733    # it will need to be balanced with a h-limited gradient.
    734734    #
    735     # For this we will use the quantity alpha as before 
     735    # For this we will use the quantity alpha as before
    736736    #
    737        
     737
    738738    #Shortcuts
    739739    wc = domain.quantities['stage'].centroid_values
    740740    zc = domain.quantities['elevation'].centroid_values
    741741    hc = wc - zc
    742    
     742
    743743    wv = domain.quantities['stage'].vertex_values
    744744    zv = domain.quantities['elevation'].vertex_values
     
    760760                 abs(zv[k,2]-zc[k]))
    761761
    762        
     762
    763763        hmin = min( hv[k,:] )
    764764
    765         #Create alpha in [0,1], where alpha==0 means using the h-limited 
     765        #Create alpha in [0,1], where alpha==0 means using the h-limited
    766766        #stage and alpha==1 means using the w-limited stage as
    767767        #computed by the gradient limiter (both 1st or 2nd order)
    768    
     768
    769769        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
    770770        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
     
    773773            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
    774774        else:
    775             #Flat bed 
     775            #Flat bed
    776776            alpha = 1.0
    777777
    778         #Let 
     778        #Let
    779779        #
    780         #  wvi be the w-limited stage (wvi = zvi + hvi)       
     780        #  wvi be the w-limited stage (wvi = zvi + hvi)
    781781        #  wvi- be the h-limited state (wvi- = zvi + hvi-)
    782         # 
    783         #   
     782        #
     783        #
    784784        #where i=0,1,2 denotes the vertex ids
    785785        #
    786         #Weighted balance between w-limited and h-limited stage is 
     786        #Weighted balance between w-limited and h-limited stage is
    787787        #
    788         #  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)   
     788        #  wvi := (1-alpha)*(zvi+hvi-) + alpha*(zvi+hvi)
    789789        #
    790790        #It follows that the updated wvi is
     
    793793        # Momentum is balanced between constant and limited
    794794
    795        
     795
    796796        #for i in range(3):
    797797        #    wv[k,i] = zv[k,i] + hvbar[k,i]
    798        
     798
    799799        #return
    800        
    801         if alpha < 1:         
    802        
     800
     801        if alpha < 1:
     802
    803803            for i in range(3):
    804804                wv[k,i] = zv[k,i] + (1-alpha)*hvbar[k,i] + alpha*hv[k,i]
    805            
     805
    806806            #Momentums at centroids
    807807            xmomc = domain.quantities['xmomentum'].centroid_values
    808             ymomc = domain.quantities['ymomentum'].centroid_values       
     808            ymomc = domain.quantities['ymomentum'].centroid_values
    809809
    810810            #Momentums at vertices
    811811            xmomv = domain.quantities['xmomentum'].vertex_values
    812             ymomv = domain.quantities['ymomentum'].vertex_values         
    813 
    814             # Update momentum as a linear combination of 
     812            ymomv = domain.quantities['ymomentum'].vertex_values
     813
     814            # Update momentum as a linear combination of
    815815            # xmomc and ymomc (shallow) and momentum
    816816            # from extrapolator xmomv and ymomv (deep).
    817             xmomv[k,:] = (1-alpha)*xmomc[k] + alpha*xmomv[k,:]           
     817            xmomv[k,:] = (1-alpha)*xmomc[k] + alpha*xmomv[k,:]
    818818            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
    819                                    
    820            
     819
     820
    821821def balance_deep_and_shallow_c(domain):
    822822    """Wrapper for C implementation
    823823    """
    824    
     824
    825825    #Shortcuts
    826826    wc = domain.quantities['stage'].centroid_values
    827827    zc = domain.quantities['elevation'].centroid_values
    828828    hc = wc - zc
    829    
     829
    830830    wv = domain.quantities['stage'].vertex_values
    831831    zv = domain.quantities['elevation'].vertex_values
     
    834834    #Momentums at centroids
    835835    xmomc = domain.quantities['xmomentum'].centroid_values
    836     ymomc = domain.quantities['ymomentum'].centroid_values       
     836    ymomc = domain.quantities['ymomentum'].centroid_values
    837837
    838838    #Momentums at vertices
    839839    xmomv = domain.quantities['xmomentum'].vertex_values
    840     ymomv = domain.quantities['ymomentum'].vertex_values         
     840    ymomv = domain.quantities['ymomentum'].vertex_values
    841841
    842842    #Limit h
    843     hvbar = h_limiter(domain)   
    844    
     843    hvbar = h_limiter(domain)
     844
    845845    #This is how one would make a first order h_limited value
    846846    #as in the old balancer (pre 17 Feb 2005):
     
    852852    from shallow_water_ext import balance_deep_and_shallow
    853853    balance_deep_and_shallow(wc, zc, hc, wv, zv, hv, hvbar,
    854                              xmomc, ymomc, xmomv, ymomv)   
    855 
    856    
     854                             xmomc, ymomc, xmomv, ymomv)
     855
     856
    857857
    858858
     
    867867    and third conserved quantities.
    868868    """
    869    
    870     def __init__(self, domain = None):       
     869
     870    def __init__(self, domain = None):
    871871        Boundary.__init__(self)
    872872
     
    874874            msg = 'Domain must be specified for reflective boundary'
    875875            raise msg
    876        
     876
    877877        #Handy shorthands
    878878        self.stage = domain.quantities['stage'].edge_values
    879879        self.xmom = domain.quantities['xmomentum'].edge_values
    880         self.ymom = domain.quantities['ymomentum'].edge_values         
     880        self.ymom = domain.quantities['ymomentum'].edge_values
    881881        self.normals = domain.normals
    882        
    883         from Numeric import zeros, Float       
    884         self.conserved_quantities = zeros(3, Float) 
    885        
     882
     883        from Numeric import zeros, Float
     884        self.conserved_quantities = zeros(3, Float)
     885
    886886    def __repr__(self):
    887887        return 'Reflective_boundary'
     
    895895        q = self.conserved_quantities
    896896        q[0] = self.stage[vol_id, edge_id]
    897         q[1] = self.xmom[vol_id, edge_id] 
    898         q[2] = self.ymom[vol_id, edge_id] 
    899        
    900         normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]     
    901 
    902        
     897        q[1] = self.xmom[vol_id, edge_id]
     898        q[2] = self.ymom[vol_id, edge_id]
     899
     900        normal = self.normals[vol_id, 2*edge_id:2*edge_id+2]
     901
     902
    903903        r = rotate(q, normal, direction = 1)
    904904        r[1] = -r[1]
     
    907907        return q
    908908
    909        
     909
    910910#class Spatio_temporal_boundary(Boundary):
    911 #    """The spatio-temporal boundary, reads values for the conserved 
    912 #    quantities from an sww NetCDF file, and returns interpolated values 
     911#    """The spatio-temporal boundary, reads values for the conserved
     912#    quantities from an sww NetCDF file, and returns interpolated values
    913913#    at the midpoints of each associated boundaty segment.
    914914#    Time dependency is interpolated linearly as in util.File_function.#
    915915#
    916916#    Example:
    917 #    Bf = Spatio_temporal_boundary('source_file.sww', domain) 
    918 #         
     917#    Bf = Spatio_temporal_boundary('source_file.sww', domain)
     918#
    919919#    """
    920920Spatio_temporal_boundary = File_boundary
    921        
    922 
    923        
     921
     922
     923
    924924
    925925#########################
     
    937937
    938938    Stage = domain.quantities['stage']
    939     Elevation = domain.quantities['elevation']   
     939    Elevation = domain.quantities['elevation']
    940940    h = Stage.edge_values - Elevation.edge_values
    941941    v = Elevation.vertex_values
    942    
     942
    943943    x = domain.get_vertex_coordinates()
    944944    g = domain.g
    945    
    946     for k in range(domain.number_of_elements):   
     945
     946    for k in range(domain.number_of_elements):
    947947        avg_h = sum( h[k,:] )/3
    948        
     948
    949949        #Compute bed slope
    950         x0, y0, x1, y1, x2, y2 = x[k,:]   
     950        x0, y0, x1, y1, x2, y2 = x[k,:]
    951951        z0, z1, z2 = v[k,:]
    952952
     
    955955        #Update momentum
    956956        xmom[k] += -g*zx*avg_h
    957         ymom[k] += -g*zy*avg_h       
     957        ymom[k] += -g*zy*avg_h
    958958
    959959
    960960def gravity_c(domain):
    961961    """Wrapper calling C version
    962     """   
     962    """
    963963
    964964    xmom = domain.quantities['xmomentum'].explicit_update
    965965    ymom = domain.quantities['ymomentum'].explicit_update
    966966
    967     Stage = domain.quantities['stage']   
    968     Elevation = domain.quantities['elevation']   
     967    Stage = domain.quantities['stage']
     968    Elevation = domain.quantities['elevation']
    969969    h = Stage.edge_values - Elevation.edge_values
    970970    v = Elevation.vertex_values
    971    
     971
    972972    x = domain.get_vertex_coordinates()
    973973    g = domain.g
    974    
    975    
     974
     975
    976976    from shallow_water_ext import gravity
    977977    gravity(g, h, v, x, xmom, ymom)
    978    
    979        
     978
     979
    980980def manning_friction(domain):
    981981    """Apply (Manning) friction to water momentum
     
    987987    z = domain.quantities['elevation'].centroid_values
    988988    h = w-z
    989    
     989
    990990    uh = domain.quantities['xmomentum'].centroid_values
    991991    vh = domain.quantities['ymomentum'].centroid_values
    992     eta = domain.quantities['friction'].centroid_values   
    993    
     992    eta = domain.quantities['friction'].centroid_values
     993
    994994    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
    995     ymom_update = domain.quantities['ymomentum'].semi_implicit_update   
    996    
     995    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
     996
    997997    N = domain.number_of_elements
    998998    eps = domain.minimum_allowed_height
    999999    g = domain.g
    1000    
     1000
    10011001    for k in range(N):
    10021002        if eta[k] >= eps:
     
    10081008                xmom_update[k] += S*uh[k]
    10091009                ymom_update[k] += S*vh[k]
    1010            
    1011        
     1010
     1011
    10121012def manning_friction_c(domain):
    10131013    """Wrapper for c version
     
    10161016
    10171017    xmom = domain.quantities['xmomentum']
    1018     ymom = domain.quantities['ymomentum']   
    1019        
     1018    ymom = domain.quantities['ymomentum']
     1019
    10201020    w = domain.quantities['stage'].centroid_values
    10211021    z = domain.quantities['elevation'].centroid_values
    1022    
     1022
    10231023    uh = xmom.centroid_values
    10241024    vh = ymom.centroid_values
    1025     eta = domain.quantities['friction'].centroid_values   
    1026    
     1025    eta = domain.quantities['friction'].centroid_values
     1026
    10271027    xmom_update = xmom.semi_implicit_update
    1028     ymom_update = ymom.semi_implicit_update   
    1029    
     1028    ymom_update = ymom.semi_implicit_update
     1029
    10301030    N = domain.number_of_elements
    10311031    eps = domain.minimum_allowed_height
     
    10501050    uh = domain.quantities['xmomentum'].centroid_values
    10511051    vh = domain.quantities['ymomentum'].centroid_values
    1052     tau = domain.quantities['linear_friction'].centroid_values   
    1053    
     1052    tau = domain.quantities['linear_friction'].centroid_values
     1053
    10541054    xmom_update = domain.quantities['xmomentum'].semi_implicit_update
    1055     ymom_update = domain.quantities['ymomentum'].semi_implicit_update   
    1056    
     1055    ymom_update = domain.quantities['ymomentum'].semi_implicit_update
     1056
    10571057    N = domain.number_of_elements
    10581058    eps = domain.minimum_allowed_height
    10591059    g = domain.g #Not necessary? Why was this added?
    1060    
     1060
    10611061    for k in range(N):
    10621062        if tau[k] >= eps:
     
    10671067                xmom_update[k] += S*uh[k]
    10681068                ymom_update[k] += S*vh[k]
    1069            
    1070        
    1071        
     1069
     1070
     1071
    10721072def check_forcefield(f):
    10731073    """Check that f is either
     
    10751075       and that it returns an array or a list of same length
    10761076       as x and y
    1077     2: a scalar   
     1077    2: a scalar
    10781078    """
    10791079
    10801080    from Numeric import ones, Float, array
    10811081
    1082    
     1082
    10831083    if callable(f):
    10841084        N = 3
    10851085        x = ones(3, Float)
    1086         y = ones(3, Float)           
     1086        y = ones(3, Float)
    10871087        try:
    10881088            q = f(1.0, x, y)
     
    10911091            #FIXME: Reconsider this semantics
    10921092            raise msg
    1093                    
     1093
    10941094        try:
    10951095            q = array(q).astype(Float)
     
    10971097            msg = 'Return value from vector function %s could ' %f
    10981098            msg += 'not be converted into a Numeric array of floats.\n'
    1099             msg += 'Specified function should return either list or array.' 
     1099            msg += 'Specified function should return either list or array.'
    11001100            raise msg
    11011101
     
    11031103        msg += 'must have same lenght as input vectors'
    11041104        assert len(q) == N, msg
    1105        
    1106     else:       
     1105
     1106    else:
    11071107        try:
    11081108            f = float(f)
     
    11111111            msg += ' or a vector function'
    11121112            raise msg
    1113     return f   
     1113    return f
    11141114
    11151115
    11161116class Wind_stress:
    11171117    """Apply wind stress to water momentum in terms of
    1118     wind speed [m/s] and wind direction [degrees]   
     1118    wind speed [m/s] and wind direction [degrees]
    11191119    """
    11201120
     
    11221122        """Initialise windfield from wind speed s [m/s]
    11231123        and wind direction phi [degrees]
    1124        
     1124
    11251125        Inputs v and phi can be either scalars or Python functions, e.g.
    11261126
     
    11281128
    11291129        #FIXME - 'normal' degrees are assumed for now, i.e. the
    1130         vector (1,0) has zero degrees. 
     1130        vector (1,0) has zero degrees.
    11311131        We may need to convert from 'compass' degrees later on and also
    11321132        map from True north to grid north.
     
    11371137            ...
    11381138            return s
    1139        
     1139
    11401140        def angle(t,x,y):
    11411141            ...
     
    11541154        can be applied, providing both quantities simultaneously.
    11551155        As in
    1156         W = Wind_stress(F), where returns (speed, angle) for each t.         
     1156        W = Wind_stress(F), where returns (speed, angle) for each t.
    11571157
    11581158        domain.forcing_terms.append(W)
     
    11601160
    11611161        from config import rho_a, rho_w, eta_w
    1162         from Numeric import array, Float               
     1162        from Numeric import array, Float
    11631163
    11641164        if len(args) == 2:
     
    11721172        else:
    11731173           #Assume info is in 2 keyword arguments
    1174        
     1174
    11751175           if len(kwargs) == 2:
    11761176               s = kwargs['s']
    11771177               phi = kwargs['phi']
    11781178           else:
    1179                raise 'Assumes two keyword arguments: s=..., phi=....'   
    1180            
     1179               raise 'Assumes two keyword arguments: s=..., phi=....'
     1180
    11811181        self.speed = check_forcefield(s)
    11821182        self.phi = check_forcefield(phi)
    1183            
     1183
    11841184        self.const = eta_w*rho_a/rho_w
    1185        
     1185
    11861186
    11871187    def __call__(self, domain):
     
    11901190
    11911191        from math import pi, cos, sin, sqrt
    1192         from Numeric import Float, ones, ArrayType 
    1193        
     1192        from Numeric import Float, ones, ArrayType
     1193
    11941194        xmom_update = domain.quantities['xmomentum'].explicit_update
    1195         ymom_update = domain.quantities['ymomentum'].explicit_update   
    1196        
     1195        ymom_update = domain.quantities['ymomentum'].explicit_update
     1196
    11971197        N = domain.number_of_elements
    1198         t = domain.time       
    1199        
     1198        t = domain.time
     1199
    12001200        if callable(self.speed):
    1201             xc = domain.get_centroid_coordinates()           
     1201            xc = domain.get_centroid_coordinates()
    12021202            s_vec = self.speed(t, xc[:,0], xc[:,1])
    12031203        else:
     
    12121212
    12131213        if callable(self.phi):
    1214             xc = domain.get_centroid_coordinates()           
     1214            xc = domain.get_centroid_coordinates()
    12151215            phi_vec = self.phi(t, xc[:,0], xc[:,1])
    12161216        else:
     
    12181218
    12191219            try:
    1220                 phi_vec = self.phi * ones(N, Float)           
     1220                phi_vec = self.phi * ones(N, Float)
    12211221            except:
    12221222                msg = 'Angle must be either callable or a scalar: %s' %self.phi
     
    12331233    """
    12341234    from math import pi, cos, sin, sqrt
    1235    
     1235
    12361236    N = len(s_vec)
    12371237    for k in range(N):
     
    12451245        u = s*cos(phi)
    12461246        v = s*sin(phi)
    1247        
     1247
    12481248        #Compute wind stress
    12491249        S = const * sqrt(u**2 + v**2)
    12501250        xmom_update[k] += S*u
    1251         ymom_update[k] += S*v       
    1252            
     1251        ymom_update[k] += S*v
     1252
    12531253
    12541254
    12551255##############################
    12561256#OBSOLETE STUFF
    1257    
     1257
    12581258def balance_deep_and_shallow_old(domain):
    12591259    """Compute linear combination between stage as computed by
     
    12681268
    12691269    #OBSOLETE
    1270    
     1270
    12711271    #Shortcuts
    12721272    wc = domain.quantities['stage'].centroid_values
    12731273    zc = domain.quantities['elevation'].centroid_values
    12741274    hc = wc - zc
    1275    
     1275
    12761276    wv = domain.quantities['stage'].vertex_values
    12771277    zv = domain.quantities['elevation'].vertex_values
     
    12801280
    12811281    #Computed linear combination between constant stages and and
    1282     #stages parallel to the bed elevation.     
     1282    #stages parallel to the bed elevation.
    12831283    for k in range(domain.number_of_elements):
    12841284        #Compute maximal variation in bed elevation
     
    12931293                 abs(zv[k,2]-zc[k]))
    12941294
    1295        
     1295
    12961296        hmin = min( hv[k,:] )
    12971297
    1298         #Create alpha in [0,1], where alpha==0 means using shallow 
     1298        #Create alpha in [0,1], where alpha==0 means using shallow
    12991299        #first order scheme and alpha==1 means using the stage w as
    13001300        #computed by the gradient limiter (1st or 2nd order)
     
    13021302        #If hmin > dz/2 then alpha = 1 and the bed will have no effect
    13031303        #If hmin < 0 then alpha = 0 reverting to constant height above bed.
    1304      
     1304
    13051305        if dz > 0.0:
    13061306            alpha = max( min( 2*hmin/dz, 1.0), 0.0 )
    13071307        else:
    1308             #Flat bed 
     1308            #Flat bed
    13091309            alpha = 1.0
    13101310
    1311         #Weighted balance between stage parallel to bed elevation 
    1312         #(wvi = zvi + hc) and stage as computed by 1st or 2nd 
     1311        #Weighted balance between stage parallel to bed elevation
     1312        #(wvi = zvi + hc) and stage as computed by 1st or 2nd
    13131313        #order gradient limiter
    13141314        #(wvi = zvi + hvi) where i=0,1,2 denotes the vertex ids
    13151315        #
    13161316        #It follows that the updated wvi is
    1317         #  wvi := (1-alpha)*(zvi+hc) + alpha*(zvi+hvi) = 
     1317        #  wvi := (1-alpha)*(zvi+hc) + alpha*(zvi+hvi) =
    13181318        #  zvi + hc + alpha*(hvi - hc)
    13191319        #
    13201320        #Note that hvi = zc+hc-zvi in the first order case (constant).
    13211321
    1322         if alpha < 1:         
     1322        if alpha < 1:
    13231323            for i in range(3):
    13241324                wv[k,i] = zv[k,i] + hc[k] + alpha*(hv[k,i]-hc[k])
    1325            
     1325
    13261326
    13271327            #Momentums at centroids
    13281328            xmomc = domain.quantities['xmomentum'].centroid_values
    1329             ymomc = domain.quantities['ymomentum'].centroid_values       
     1329            ymomc = domain.quantities['ymomentum'].centroid_values
    13301330
    13311331            #Momentums at vertices
    13321332            xmomv = domain.quantities['xmomentum'].vertex_values
    1333             ymomv = domain.quantities['ymomentum'].vertex_values         
    1334 
    1335             # Update momentum as a linear combination of 
     1333            ymomv = domain.quantities['ymomentum'].vertex_values
     1334
     1335            # Update momentum as a linear combination of
    13361336            # xmomc and ymomc (shallow) and momentum
    13371337            # from extrapolator xmomv and ymomv (deep).
    1338             xmomv[k,:] = (1-alpha)*xmomc[k] + alpha*xmomv[k,:]           
     1338            xmomv[k,:] = (1-alpha)*xmomc[k] + alpha*xmomv[k,:]
    13391339            ymomv[k,:] = (1-alpha)*ymomc[k] + alpha*ymomv[k,:]
    1340            
     1340
    13411341
    13421342
     
    13531353    x,y are assumed to be in the unit square
    13541354    """
    1355    
     1355
    13561356    def __init__(self, stage):
    13571357        self.inflow_stage = stage
    13581358
    1359     def __call__(self, x, y):   
     1359    def __call__(self, x, y):
    13601360        from Numeric import zeros, Float
    13611361        from math import sqrt
    1362    
     1362
    13631363        N = len(x)
    1364         assert N == len(y)   
     1364        assert N == len(y)
    13651365
    13661366        z = zeros(N, Float)
     
    13701370            #Flattish bit to the left
    13711371            if x[i] < 0.3:
    1372                 z[i] = -x[i]/10 
    1373            
     1372                z[i] = -x[i]/10
     1373
    13741374            #Weir
    13751375            if x[i] >= 0.3 and x[i] < 0.4:
     
    13811381            depth = -1.0
    13821382            #plateaux = -0.9
    1383             plateaux = -0.6           
     1383            plateaux = -0.6
    13841384            if y[i] < 0.7:
    13851385                if x[i] > x0 and x[i] < 0.9:
     
    13891389                if x[i] >= 0.9:
    13901390                    z[i] = plateaux
    1391                    
    1392                    
     1391
     1392
    13931393            elif y[i] >= 0.7 and y[i] < 1.5:
    13941394                #Restrict and deepen
     
    13971397                    #z[i] = depth-y[i]/5
    13981398                    #z[i] = depth
    1399                 elif x[i] >= 0.8:   
     1399                elif x[i] >= 0.8:
    14001400                    #RHS plateaux
    14011401                    z[i] = plateaux
    1402                    
     1402
    14031403            elif y[i] >= 1.5:
    14041404                if x[i] >= x0 and x[i] < 0.8 + (y[i]-1.5)/1.2:
    14051405                    #Widen up and stay at constant depth
    14061406                    z[i] = depth-1.5/5
    1407                 elif x[i] >= 0.8 + (y[i]-1.5)/1.2:                       
     1407                elif x[i] >= 0.8 + (y[i]-1.5)/1.2:
    14081408                    #RHS plateaux
    1409                     z[i] = plateaux                                   
    1410                    
     1409                    z[i] = plateaux
     1410
    14111411
    14121412            #Hole in weir (slightly higher than inflow condition)
     
    14181418            if x[i] >= 0.4 and x[i] < x0 and y[i] > 0.2 and y[i] < 0.4:
    14191419                z[i] = -x[i]+self.inflow_stage + 0.02
    1420                
     1420
    14211421            if x[i] >= x0 and x[i] < 0.6 and y[i] > 0.2 and y[i] < 0.4:
    14221422                #Flatten it out towards the end
     
    14321432            if x[i] >= 1.14 and x[i] < 1.2 and y[i] >= 0.4 and y[i] < 0.6:
    14331433                z[i] = -0.9 #North south
    1434                
     1434
    14351435            if x[i] >= 0.9 and x[i] < 1.18 and y[i] >= 0.58 and y[i] < 0.65:
    14361436                z[i] = -1.0 + (x[i]-0.9)/3 #East west
    1437            
    1438            
     1437
     1438
    14391439
    14401440            #Stuff not in use
    1441            
     1441
    14421442            #Upward slope at inlet to the north west
    14431443            #if x[i] < 0.0: # and y[i] > 0.5:
     
    14601460    x,y are assumed to be in the unit square
    14611461    """
    1462    
     1462
    14631463    def __init__(self, stage):
    14641464        self.inflow_stage = stage
    14651465
    1466     def __call__(self, x, y):   
    1467         from Numeric import zeros, Float 
    1468    
     1466    def __call__(self, x, y):
     1467        from Numeric import zeros, Float
     1468
    14691469        N = len(x)
    1470         assert N == len(y)   
     1470        assert N == len(y)
    14711471
    14721472        z = zeros(N, Float)
     
    14771477            if x[i] < 0.3:
    14781478                z[i] = -x[i]/10  #General slope
    1479            
     1479
    14801480            #Weir
    14811481            if x[i] > 0.3 and x[i] < 0.4:
     
    14881488            #Hole in weir (slightly higher than inflow condition)
    14891489            if x[i] > 0.3 and x[i] < 0.4 and y[i] > 0.2 and y[i] < 0.4:
    1490                 z[i] = -x[i]+self.inflow_stage + 0.05       
    1491            
     1490                z[i] = -x[i]+self.inflow_stage + 0.05
     1491
    14921492
    14931493        return z/2
    1494        
    1495 
    1496            
     1494
     1495
     1496
    14971497class Constant_height:
    14981498    """Set an initial condition with constant water height, e.g
     
    15211521    Fluxes across each edge are scaled by edgelengths and summed up
    15221522    Resulting flux is then scaled by area and stored in
    1523     explicit_update for each of the three conserved quantities 
    1524     stage, xmomentum and ymomentum   
     1523    explicit_update for each of the three conserved quantities
     1524    stage, xmomentum and ymomentum
    15251525
    15261526    The maximal allowable speed computed by the flux_function for each volume
     
    15301530    Post conditions:
    15311531      domain.explicit_update is reset to computed flux values
    1532       domain.timestep is set to the largest step satisfying all volumes. 
     1532      domain.timestep is set to the largest step satisfying all volumes.
    15331533    """
    15341534
     
    15371537
    15381538    N = domain.number_of_elements
    1539    
     1539
    15401540    #Shortcuts
    15411541    Stage = domain.quantities['stage']
    15421542    Xmom = domain.quantities['xmomentum']
    15431543    Ymom = domain.quantities['ymomentum']
    1544     Bed = domain.quantities['elevation']       
     1544    Bed = domain.quantities['elevation']
    15451545
    15461546    #Arrays
     
    15481548    xmom =  Xmom.edge_values
    15491549    ymom =  Ymom.edge_values
    1550     bed =   Bed.edge_values   
     1550    bed =   Bed.edge_values
    15511551
    15521552    stage_bdry = Stage.boundary_values
    15531553    xmom_bdry =  Xmom.boundary_values
    15541554    ymom_bdry =  Ymom.boundary_values
    1555    
     1555
    15561556    flux = zeros((N,3), Float) #Work array for summing up fluxes
    15571557
    15581558    #Loop
    1559     timestep = float(sys.maxint)   
     1559    timestep = float(sys.maxint)
    15601560    for k in range(N):
    15611561
     
    15661566
    15671567            #Quantities at neighbour on nearest face
    1568             n = domain.neighbours[k,i] 
     1568            n = domain.neighbours[k,i]
    15691569            if n < 0:
    15701570                m = -n-1 #Convert negative flag to index
    15711571                qr = [stage_bdry[m], xmom_bdry[m], ymom_bdry[m]]
    15721572                zr = zl #Extend bed elevation to boundary
    1573             else:   
     1573            else:
    15741574                m = domain.neighbour_edges[k,i]
    15751575                qr = [stage[n, m], xmom[n, m], ymom[n, m]]
    1576                 zr = bed[n, m]               
    1577 
    1578                
    1579             #Outward pointing normal vector   
     1576                zr = bed[n, m]
     1577
     1578
     1579            #Outward pointing normal vector
    15801580            normal = domain.normals[k, 2*i:2*i+2]
    15811581
    15821582            #Flux computation using provided function
    15831583            edgeflux, max_speed = flux_function(normal, ql, qr, zl, zr)
    1584        
     1584
    15851585            flux[k,:] = edgeflux
    15861586
    15871587    return flux
    1588    
    1589  
     1588
     1589
    15901590
    15911591
     
    16001600if compile.can_use_C_extension('shallow_water_ext.c'):
    16011601    #Replace python version with c implementations
    1602    
     1602
    16031603    from shallow_water_ext import rotate, assign_windfield_values
    16041604    compute_fluxes = compute_fluxes_c
     
    16091609    protect_against_infinitesimal_and_negative_heights = protect_against_infinitesimal_and_negative_heights_c
    16101610
    1611    
     1611
    16121612    #distribute_to_vertices_and_edges = distribute_to_vertices_and_edges_c
    16131613
     
    16311631        psyco.bind(Domain.distribute_to_vertices_and_edges)
    16321632        psyco.bind(Domain.compute_fluxes)
    1633        
     1633
    16341634if __name__ == "__main__":
    16351635    pass
Note: See TracChangeset for help on using the changeset viewer.